aboutsummaryrefslogtreecommitdiff
path: root/share/examples
diff options
context:
space:
mode:
Diffstat (limited to 'share/examples')
-rw-r--r--share/examples/BSD_daemon/FreeBSD.pfa32
-rw-r--r--share/examples/BSD_daemon/README83
-rw-r--r--share/examples/BSD_daemon/beastie.eps1507
-rw-r--r--share/examples/BSD_daemon/beastie.fig270
-rw-r--r--share/examples/BSD_daemon/beastie.svg46
-rw-r--r--share/examples/BSD_daemon/beastie2.eps2470
-rw-r--r--share/examples/BSD_daemon/eps.patch35
-rw-r--r--share/examples/BSD_daemon/poster.sh64
-rw-r--r--share/examples/FreeBSD_version/FreeBSD_version.c20
-rw-r--r--share/examples/FreeBSD_version/Makefile9
-rw-r--r--share/examples/FreeBSD_version/README4
-rw-r--r--share/examples/Makefile419
-rw-r--r--share/examples/Makefile.depend10
-rwxr-xr-xshare/examples/bhyve/vmrun.sh410
-rw-r--r--share/examples/bootforth/README33
-rw-r--r--share/examples/bootforth/boot.4th21
-rw-r--r--share/examples/bootforth/frames.4th88
-rw-r--r--share/examples/bootforth/loader.rc33
-rw-r--r--share/examples/bootforth/menu.4th98
-rw-r--r--share/examples/bootforth/menuconf.4th109
-rw-r--r--share/examples/bootforth/screen.4th35
-rw-r--r--share/examples/csh/dot.cshrc139
-rw-r--r--share/examples/drivers/README42
-rwxr-xr-xshare/examples/drivers/make_device_driver.sh1005
-rw-r--r--share/examples/drivers/make_pseudo_driver.sh435
-rw-r--r--share/examples/etc/README.examples69
-rw-r--r--share/examples/etc/bsd-style-copyright28
-rw-r--r--share/examples/etc/make.conf280
-rw-r--r--share/examples/find_interface/Makefile7
-rw-r--r--share/examples/find_interface/README9
-rw-r--r--share/examples/find_interface/find_interface.c109
-rw-r--r--share/examples/flua/libjail.lua105
-rwxr-xr-xshare/examples/hast/ucarp.sh70
-rwxr-xr-xshare/examples/hast/ucarp_down.sh99
-rwxr-xr-xshare/examples/hast/ucarp_up.sh106
-rwxr-xr-xshare/examples/hast/vip-down.sh4
-rwxr-xr-xshare/examples/hast/vip-up.sh6
-rw-r--r--share/examples/hwpmc/Makefile10
-rw-r--r--share/examples/hwpmc/README5
-rw-r--r--share/examples/hwpmc/overhead.c104
-rw-r--r--share/examples/indent/indent.pro46
-rw-r--r--share/examples/ipfilter/BNF81
-rw-r--r--share/examples/ipfilter/Makefile31
-rw-r--r--share/examples/ipfilter/Makefile.depend10
-rw-r--r--share/examples/ipfilter/README14
-rw-r--r--share/examples/ipfilter/example.1461
-rw-r--r--share/examples/ipfilter/examples.txt514
-rw-r--r--share/examples/ipfilter/firewall.135
-rw-r--r--share/examples/ipfilter/firewall.269
-rw-r--r--share/examples/ipfilter/ipf-howto.txt3167
-rw-r--r--share/examples/ipfilter/ipf.conf.permissive29
-rw-r--r--share/examples/ipfilter/ipf.conf.restrictive76
-rw-r--r--share/examples/ipfilter/ipf.conf.sample18
-rw-r--r--share/examples/ipfilter/ipnat.conf.sample2
-rw-r--r--share/examples/ipfilter/l4check/Makefile10
-rw-r--r--share/examples/ipfilter/l4check/http.check2
-rw-r--r--share/examples/ipfilter/l4check/http.ok1
-rw-r--r--share/examples/ipfilter/l4check/l4check.c800
-rw-r--r--share/examples/ipfilter/l4check/l4check.conf31
-rw-r--r--share/examples/ipfilter/mkfilters116
-rw-r--r--share/examples/ipfilter/mkfilters.115
-rw-r--r--share/examples/ipfilter/mlfk_rule.c69
-rw-r--r--share/examples/ipfilter/rules.txt181
-rw-r--r--share/examples/ipfilter/rules/BASIC.NAT46
-rw-r--r--share/examples/ipfilter/rules/BASIC_1.FW99
-rw-r--r--share/examples/ipfilter/rules/BASIC_2.FW72
-rw-r--r--share/examples/ipfilter/rules/example.14
-rw-r--r--share/examples/ipfilter/rules/example.1012
-rw-r--r--share/examples/ipfilter/rules/example.1126
-rw-r--r--share/examples/ipfilter/rules/example.1217
-rw-r--r--share/examples/ipfilter/rules/example.1317
-rw-r--r--share/examples/ipfilter/rules/example.25
-rw-r--r--share/examples/ipfilter/rules/example.340
-rw-r--r--share/examples/ipfilter/rules/example.44
-rw-r--r--share/examples/ipfilter/rules/example.525
-rw-r--r--share/examples/ipfilter/rules/example.65
-rw-r--r--share/examples/ipfilter/rules/example.712
-rw-r--r--share/examples/ipfilter/rules/example.810
-rw-r--r--share/examples/ipfilter/rules/example.912
-rw-r--r--share/examples/ipfilter/rules/example.sr61
-rw-r--r--share/examples/ipfilter/rules/firewall39
-rw-r--r--share/examples/ipfilter/rules/ftp-proxy45
-rwxr-xr-xshare/examples/ipfilter/rules/ftppxy6
-rw-r--r--share/examples/ipfilter/rules/ip_rules3
-rw-r--r--share/examples/ipfilter/rules/ipmon.conf25
-rw-r--r--share/examples/ipfilter/rules/nat-setup77
-rw-r--r--share/examples/ipfilter/rules/nat.eg14
-rw-r--r--share/examples/ipfilter/rules/pool.conf4
-rw-r--r--share/examples/ipfilter/rules/server11
-rw-r--r--share/examples/ipfilter/rules/tcpstate13
-rw-r--r--share/examples/ipfilter/samples/Makefile24
-rw-r--r--share/examples/ipfilter/samples/ipfilter-pb.gifbin0 -> 795 bytes
-rw-r--r--share/examples/ipfilter/samples/proxy.c316
-rw-r--r--share/examples/ipfilter/samples/relay.c195
-rw-r--r--share/examples/ipfilter/samples/userauth.c61
-rwxr-xr-xshare/examples/ipfw/change_rules.sh154
-rw-r--r--share/examples/jails/README66
-rw-r--r--share/examples/jails/VIMAGE58
-rw-r--r--share/examples/jails/jail.xxx.conf34
-rwxr-xr-xshare/examples/jails/jib417
-rwxr-xr-xshare/examples/jails/jng508
-rw-r--r--share/examples/jails/rc.conf.jails75
-rw-r--r--share/examples/jails/rcjail.xxx.conf24
-rw-r--r--share/examples/kld/Makefile73
-rw-r--r--share/examples/kld/cdev/Makefile8
-rw-r--r--share/examples/kld/cdev/README130
-rw-r--r--share/examples/kld/cdev/module/Makefile8
-rw-r--r--share/examples/kld/cdev/module/cdev.c182
-rw-r--r--share/examples/kld/cdev/module/cdev.h81
-rw-r--r--share/examples/kld/cdev/module/cdevmod.c146
-rw-r--r--share/examples/kld/cdev/test/Makefile96
-rw-r--r--share/examples/kld/cdev/test/testcdev.c125
-rw-r--r--share/examples/kld/dyn_sysctl/Makefile7
-rw-r--r--share/examples/kld/dyn_sysctl/README6
-rw-r--r--share/examples/kld/dyn_sysctl/dyn_sysctl.c167
-rw-r--r--share/examples/kld/firmware/Makefile6
-rw-r--r--share/examples/kld/firmware/README17
-rw-r--r--share/examples/kld/firmware/fwconsumer/Makefile7
-rw-r--r--share/examples/kld/firmware/fwconsumer/fw_consumer.c77
-rw-r--r--share/examples/kld/firmware/fwimage/Makefile12
-rw-r--r--share/examples/kld/firmware/fwimage/firmware.img.uu15
-rw-r--r--share/examples/kld/khelp/Makefile12
-rw-r--r--share/examples/kld/khelp/README5
-rw-r--r--share/examples/kld/khelp/h_example.c153
-rw-r--r--share/examples/kld/random_adaptor/Makefile7
-rw-r--r--share/examples/kld/random_adaptor/random_adaptor_example.c124
-rw-r--r--share/examples/kld/syscall/Makefile8
-rw-r--r--share/examples/kld/syscall/module/Makefile8
-rw-r--r--share/examples/kld/syscall/module/syscall.c83
-rw-r--r--share/examples/kld/syscall/test/Makefile9
-rw-r--r--share/examples/kld/syscall/test/call.c51
-rw-r--r--share/examples/libifconfig/Makefile10
-rw-r--r--share/examples/libifconfig/ifchangevlan.c107
-rw-r--r--share/examples/libifconfig/ifcreate.c94
-rw-r--r--share/examples/libifconfig/ifcreatevlan.c103
-rw-r--r--share/examples/libifconfig/ifdestroy.c88
-rw-r--r--share/examples/libifconfig/setdescription.c96
-rw-r--r--share/examples/libifconfig/setmtu.c96
-rw-r--r--share/examples/libifconfig/status.c537
-rw-r--r--share/examples/libusb20/Makefile16
-rw-r--r--share/examples/libusb20/README40
-rw-r--r--share/examples/libusb20/bulk.c244
-rw-r--r--share/examples/libusb20/control.c416
-rw-r--r--share/examples/libusb20/util.c48
-rw-r--r--share/examples/libusb20/util.h12
-rw-r--r--share/examples/libvgl/Makefile9
-rw-r--r--share/examples/libvgl/Makefile.depend17
-rw-r--r--share/examples/libvgl/demo.c122
-rw-r--r--share/examples/mdoc/POSIX-copyright36
-rw-r--r--share/examples/mdoc/deshallify.sh75
-rw-r--r--share/examples/mdoc/example.1155
-rw-r--r--share/examples/mdoc/example.3335
-rw-r--r--share/examples/mdoc/example.4123
-rw-r--r--share/examples/mdoc/example.9343
-rw-r--r--share/examples/modules/Makefile6
-rw-r--r--share/examples/modules/skel.c86
-rw-r--r--share/examples/netgraph/ether.bridge169
-rw-r--r--share/examples/netgraph/frame_relay45
-rw-r--r--share/examples/netgraph/ngctl172
-rw-r--r--share/examples/netgraph/raw15
-rw-r--r--share/examples/netgraph/udp.tunnel52
-rw-r--r--share/examples/netgraph/virtual.chain369
-rw-r--r--share/examples/netgraph/virtual.lan358
-rw-r--r--share/examples/perfmon/Makefile9
-rw-r--r--share/examples/perfmon/README23
-rw-r--r--share/examples/perfmon/perfmon.c191
-rw-r--r--share/examples/pf/Makefile10
-rw-r--r--share/examples/pf/Makefile.depend10
-rw-r--r--share/examples/pf/ackpri30
-rw-r--r--share/examples/pf/faq-example150
-rw-r--r--share/examples/pf/faq-example288
-rw-r--r--share/examples/pf/faq-example3116
-rw-r--r--share/examples/pf/pf.conf34
-rw-r--r--share/examples/pf/queue120
-rw-r--r--share/examples/pf/queue228
-rw-r--r--share/examples/pf/queue315
-rw-r--r--share/examples/pf/queue419
-rw-r--r--share/examples/pf/spamd7
-rw-r--r--share/examples/ppi/Makefile9
-rw-r--r--share/examples/ppi/ppilcd.c436
-rwxr-xr-xshare/examples/ppp/chap-auth96
-rwxr-xr-xshare/examples/ppp/login-auth73
-rw-r--r--share/examples/ppp/ppp.conf.sample788
-rw-r--r--share/examples/ppp/ppp.conf.span-isp193
-rw-r--r--share/examples/ppp/ppp.conf.span-isp.working106
-rw-r--r--share/examples/ppp/ppp.linkdown.sample33
-rw-r--r--share/examples/ppp/ppp.linkdown.span-isp16
-rw-r--r--share/examples/ppp/ppp.linkdown.span-isp.working16
-rw-r--r--share/examples/ppp/ppp.linkup.sample53
-rw-r--r--share/examples/ppp/ppp.linkup.span-isp16
-rw-r--r--share/examples/ppp/ppp.linkup.span-isp.working16
-rw-r--r--share/examples/ppp/ppp.secret.sample40
-rw-r--r--share/examples/ppp/ppp.secret.span-isp5
-rw-r--r--share/examples/ppp/ppp.secret.span-isp.working8
-rw-r--r--share/examples/printing/diablo-if-net7
-rw-r--r--share/examples/printing/hpdf59
-rw-r--r--share/examples/printing/hpif11
-rw-r--r--share/examples/printing/hpof8
-rw-r--r--share/examples/printing/hprf8
-rw-r--r--share/examples/printing/hpvf9
-rw-r--r--share/examples/printing/if-simple9
-rw-r--r--share/examples/printing/if-simpleX10
-rw-r--r--share/examples/printing/ifhp32
-rw-r--r--share/examples/printing/make-ps-header79
-rw-r--r--share/examples/printing/netprint24
-rw-r--r--share/examples/printing/psdf8
-rw-r--r--share/examples/printing/psdfX31
-rw-r--r--share/examples/printing/psif23
-rw-r--r--share/examples/printing/pstf6
-rw-r--r--share/examples/printing/pstfX6
-rw-r--r--share/examples/scsi_target/Makefile11
-rw-r--r--share/examples/scsi_target/scsi_cmds.c813
-rw-r--r--share/examples/scsi_target/scsi_target.8156
-rw-r--r--share/examples/scsi_target/scsi_target.c986
-rw-r--r--share/examples/scsi_target/scsi_target.h129
-rw-r--r--share/examples/ses/Makefile39
-rw-r--r--share/examples/ses/Makefile.inc40
-rw-r--r--share/examples/ses/getencstat/Makefile42
-rw-r--r--share/examples/ses/getencstat/getencstat.081
-rw-r--r--share/examples/ses/sesd/Makefile42
-rw-r--r--share/examples/ses/sesd/sesd.086
-rw-r--r--share/examples/ses/setencstat/Makefile42
-rw-r--r--share/examples/ses/setencstat/setencstat.071
-rw-r--r--share/examples/ses/setobjstat/Makefile42
-rw-r--r--share/examples/ses/setobjstat/setobjstat.068
-rw-r--r--share/examples/ses/srcs/chpmon.c125
-rw-r--r--share/examples/ses/srcs/eltsub.c189
-rw-r--r--share/examples/ses/srcs/eltsub.h35
-rw-r--r--share/examples/ses/srcs/getencstat.c195
-rw-r--r--share/examples/ses/srcs/getnobj.c66
-rw-r--r--share/examples/ses/srcs/getobjmap.c87
-rw-r--r--share/examples/ses/srcs/getobjstat.c76
-rw-r--r--share/examples/ses/srcs/inienc.c61
-rw-r--r--share/examples/ses/srcs/sesd.c176
-rw-r--r--share/examples/ses/srcs/setencstat.c68
-rw-r--r--share/examples/ses/srcs/setobjstat.c83
-rw-r--r--share/examples/smbfs/Makefile10
-rw-r--r--share/examples/smbfs/Makefile.depend10
-rw-r--r--share/examples/smbfs/print/Makefile8
-rw-r--r--share/examples/smbfs/print/Makefile.depend10
-rw-r--r--share/examples/sound/README66
-rw-r--r--share/examples/sound/basic.c99
-rw-r--r--share/examples/sound/midi.c76
-rw-r--r--share/examples/sound/ossinit.h262
-rw-r--r--share/examples/sound/ossmidi.h63
-rw-r--r--share/examples/sunrpc/Makefile25
-rw-r--r--share/examples/sunrpc/dir/Makefile25
-rw-r--r--share/examples/sunrpc/dir/dir.x36
-rw-r--r--share/examples/sunrpc/dir/dir_proc.c54
-rw-r--r--share/examples/sunrpc/dir/rls.c80
-rw-r--r--share/examples/sunrpc/msg/Makefile35
-rw-r--r--share/examples/sunrpc/msg/msg.x8
-rw-r--r--share/examples/sunrpc/msg/msg_proc.c28
-rw-r--r--share/examples/sunrpc/msg/printmsg.c43
-rw-r--r--share/examples/sunrpc/msg/rprintmsg.c73
-rw-r--r--share/examples/sunrpc/sort/Makefile34
-rw-r--r--share/examples/sunrpc/sort/rsort.c42
-rw-r--r--share/examples/sunrpc/sort/sort.x18
-rw-r--r--share/examples/sunrpc/sort/sort_proc.c26
-rw-r--r--share/examples/tests/Makefile7
-rw-r--r--share/examples/tests/Makefile.depend10
-rw-r--r--share/examples/tests/README36
-rw-r--r--share/examples/tests/tests/Makefile35
-rw-r--r--share/examples/tests/tests/Makefile.depend10
-rw-r--r--share/examples/tests/tests/atf/Kyuafile45
-rw-r--r--share/examples/tests/tests/atf/Makefile52
-rw-r--r--share/examples/tests/tests/atf/Makefile.depend17
-rw-r--r--share/examples/tests/tests/atf/cp_test.sh120
-rw-r--r--share/examples/tests/tests/atf/printf_test.c158
-rw-r--r--share/examples/tests/tests/googletest/Makefile58
-rw-r--r--share/examples/tests/tests/plain/Kyuafile46
-rw-r--r--share/examples/tests/tests/plain/Makefile52
-rw-r--r--share/examples/tests/tests/plain/Makefile.depend16
-rw-r--r--share/examples/tests/tests/plain/cp_test.sh83
-rw-r--r--share/examples/tests/tests/plain/printf_test.c121
-rw-r--r--share/examples/tests/tests/tap/Kyuafile46
-rw-r--r--share/examples/tests/tests/tap/Makefile52
-rw-r--r--share/examples/tests/tests/tap/Makefile.depend16
-rw-r--r--share/examples/tests/tests/tap/cp_test.sh97
-rw-r--r--share/examples/tests/tests/tap/printf_test.c184
-rwxr-xr-xshare/examples/uefisign/uefikeys36
-rw-r--r--share/examples/witness/lockgraphs.sh23
-rw-r--r--share/examples/ypldap/ypldap.conf39
283 files changed, 31642 insertions, 0 deletions
diff --git a/share/examples/BSD_daemon/FreeBSD.pfa b/share/examples/BSD_daemon/FreeBSD.pfa
new file mode 100644
index 000000000000..bcd7c70aff63
--- /dev/null
+++ b/share/examples/BSD_daemon/FreeBSD.pfa
@@ -0,0 +1,32 @@
+%!PS-AdobeFont-1.0: (FreeBSD) 001.003
+%$FreeBSD$
+%Created by NRB Systems
+10 dict begin
+/FontInfo 9 dict dup begin
+/version (001.003) readonly def
+/FullName (FreeBSD Bold) readonly def
+/FamilyName (FreeBSD) readonly def
+/Weight (Bold) readonly def
+/ItalicAngle 0 def
+/isFixedPitch false def
+/UnderlinePosition -113 def
+/UnderlineThickness 96 def
+/Notice (Free font with FreeBSD.) readonly def
+end readonly def
+/FontName /FreeBSD def
+/PaintType 0 def
+/FontType 1 def
+/FontMatrix [0.001 0 0 0.001 0 0] readonly def
+/FontBBox {-167 -236 1410 963 }readonly def
+/Encoding StandardEncoding def
+currentdict end
+currentfile eexec
+f0f0f0f011ee838241a0cec525a60ce01562fd01753ef17c08b804c2190d1aa4d3d7a12f3062687674aa2a92cf8242c0f344f7c7ff68f4dfea2890ffb217b7cfa0dc6862b09b5ec7382b9d9919be8dfa2ad48e471b50ed4f50092fd1b56974c018419c73755c5dd5db8b4a67edc9172c690e4d9554f8e038edbdaeca3f244f0f3f6f82fe5413751afdc1ff2ef33bc43f20a9b5db88ca37c067e2579f6237b5a64aff20041d5aa4a925c9f299ba942510249706a455aeb0441beb17ff67c90c618b823b3b9293fe399139c747d6675013b85dd4d7d53e532028c93e07edc9c1735332b79106ae1f6f0a2a421d2a10dfe430cc505331f5285400bac5b960c568e46bc60424cc7556af3ab80eed5068afa949d01aefa15a3635553b4d965c83f5321a0bab542b3ad3f05ca5a4e80771ea7dac758b3fb0281cd6473439050c4f3e7885bcdef7ed3d9be1528d2c035f25cda0ff44ab6d715cfa66af54087cdcc7cbcc8e92b3336acffc0486603c1bed8575b54104fb7aa35a3468aa96e14575833f832bd9c8ac4b41547fd5611878fba5911a73e2d96ed3d59abef1f0a250f0cefcee604733a7f538e5cda3c343401c6ca1bcc4948dd1d4cd045021df7ea5210a5f251a26202a24a16b6ae59ea7ef139883199bd2a490557aa0c2390283e10c826084239c39f6ea1b1e72f374ef7a6ce53480ddb967b2b2324834fe0419ea2c384b5e78ca3cc603cd05e18747fa2ca764904b60244cedc0fa74e54798785f812417c1770b4957ec91a2a25409bdb6f0b0af166f49d28f9c0774a589ba28526bbd0f665c339dd6cdb25e642beb864e1662f9ace50434fb76cd5546a78f8194f802b0ea4ce5f70e3b3dc05f80449b6f10bd78e3fae5a72f5428080e27bc58bc9905b8484973d53e6a6a41e0ca8e436629e4f649775d7e8a0a88c81940e22e332300b9475c66f25369840e0f72cd01c070c8667d5c0f8c8112af0f1aa6db12206b0722787891641c1e727c2e87cc401fa57340ae78e592ad8e2bc3b53657faf641973565fbaf90a44eab3388c0600dbf26a8d3405ec28f0fb9b82a4d3542000663d09224b7796d5881643cfb04bbee1b1c42528bdb2050b07c5a069a38d9dccdede2403dcd9b4573f53c4b37bb400c5f8f09c48e0edf917b1b38ee8871f61f289a4953b529adc4a2215f25770d0a4a2042a0fa54aca3afc4e6d4160ab84621f15c186c054169bcda02740d0a75201a68dc12f774826fe6fecde716fae9aafecbe5a10d0a732027439113c180e348426805353eb7448230c4611b0d0a7420949fb81757802e694b71a36a3f4d7235720d0a20204bf97720c2077fd1f95f57638711e28c333fda3ef2715c3329fc0d0a6b206238bf6952f35dd90c1a82c221915394abc594c83725697b35e3fdb00e6d5249bfe459a56f9b92fa8f0d0a65204b9711ad986dcdad852ce1b3fee159a7bd1bc1b8d4d40f800d0a65209ca7a2e007d4c7baf438865a2e88246978e9b1770d0a7020c396208dc65cb425042298200de19882b5a30db439654e06b1190d0a2020711958391b2c7f46c3adfb6e97b42a679029d8912ad08cc15fbd810215967e4fd40d0a6520fc7afc363bd4fd6bebce2630021597309113785b7dc875a0e71958b00d0a7820cc40b6c2e94a5977ebae9525a0f64d98a0d0401ad315690d4b9f6d550fe60d0a61209db21491114b877e71a69d674a6ea17eb8110d0a6d20289e64fa978047f8bd11704c674e0adf52624a7974f93ead75fc26b7c15ee0ea5b9a3ff90d0a6920ca27e2872590202d9e6e099ea9facbc85ead0964f8b737d0db9a5dc7384f5cbc6d79fe0d0a6e206bcc41e1962873d6c7f74453c82f5f25f7b311683dfd6f145d930d0a69205b0bd00c62cb912b1ce63f83dc6331456da0aeb62bf9f89d2f003cecad652e6d0d0a6e20d5af618d1e41770b42b9a269a587593874c4b35e31e6f1e40c7f0d0a6720714b7e71ab6e47018b51ed68c2bd71e4c491c6c99ebde984af511ec5fe31379ae9ec40920f7e0d0a2020beb1bdde2adef7119a3e9eeea099a51232af8e99613b84d3efeb0ae280268130de65ac30e90d0a6520ea14ee07dbee79a7012a045ff72e07a6aada6252690d0a7620c755ad4338be2fd18651a9d59bcae5b796dd0d0a652034cddd542863a58c6206b1eeaef9ff6645372af3f12872a0d18df926b5c0e69337b68e1bbb0d0a7220edc4e7f756f1d3be73aba324ad4ccdce0cd13f54f0f6fa6cfd46a4849d900d0a79207c571000f99aa9868eadfca224c4256a7cec0d0a2020ceddbb7223bce0d304d061286369a7305c696ae58d19d8317b77dcb77f7619eedabeab560d0a6c208b55bb029cfc67ec7b00cd034d2f82c1d450a5ec384e9b78fa5a7a611d88f9a856e64b0d0a6f20d2f751deba1aeb0a213347487f00081a0c911f1eee6bb7537935a10f4d0d0a772078a005da145704f706e9b46496e6d4530e353e5270d5fa6599b8d532625a2d0d0a20206ef91fbfe46fcb9dcf84d90b96ed207bdde15164357c900c9724010d0a6220681e686171539643482a58049f71949a181fa5e76b01c282fe0d0a69204e253812773456c004e417b9df2607b03971671426567a6aaa2eff0d0a642096817660b4418060acb4d05c25dbf155221dc14f9c9d582ecc0d0a2020401b77185cfecda1a53e81c8846980ec5c1483030f68f5a508330d0a71200f91ce6d9bdea78b2dff4a307354bef1b3f1b828f05bf3cb50c3c6e5f571a5469cd4d86874f0d4020d0a75207e73563dc4e2094c7d30749f93af8ef33485035bd4c4788a6af06a0c0cbae60d0a6f209efdbc6cff3aca5f89463ef6d0cdd24db08ad0716603d80d0a74203c4d00ee3f42b3bb134b62fcd6ca9744270fbe2879fefac07d2da7decbd612e1931ec9198b0d0a6520617f2a7e967646965e5b1ff71f130c31ed8eee2707268900c878160d0a642044af9dd9b1a5673f929db0b130e9f217ed926d3c7739e2ee3d0d0a20204e6bafd2d4e82b074ad64010ef0d1a0c716b559a93ff1f34fd30c6a7ed4b0d0a6620c06cdf04a317aa801a46bca9e0ae096546ea03e3ed75650d0a6f2064675d5c812a37771bb20adcfa37c13eee756870a340c251373f0d0a722020f707cdac1ba6f97723db63fea574cbe1d268bc7ced3522a6031e0d0a20203e442d77f6f3317c610da752063cd81e9dfed1533d2d2e65e322d148dc010d177b13c552efa8389b1af013ebcbff2cf16df3f7322a8a210d0a7a2064aa30c077b23638ccb725d4ab0c34044dee581c375598b6c439a2e90bae42b9102a77305b0d0a6920a28fdc09e4ca1b0f9675755a34d5e82516c126b833389426702996af7158d205862f670d0a6e20238224b151c8f2a2fa481dfdf6327ee29107319d27f74411dbf04b2d213c0d0a63205808f3022b12a49af53e8860eaacba07e9ae56ab54d683c2409564bb0d0a202054832f18a697a20e14fa1570f35ac823df21a5eeba2f510fcbade4fbe09b0d0a6520236c97f67cb16f5ddfc1d597f36e8f834e7fcc4c523d9411aa8091d5b8840d0a74209b6858fe1699fd9be7654683a71df52411e11b9948e08a8d95120d0a63206f111b8a97eb1d4a853769204cb0e85e66c882c0aab0e95e2885e9683ecd0d0a682029e71b2021a94e5bdd6463981c89f3ecdc31ced1210b5f052cec0d0a6920bcb172b7c7994a2095cf040c623904f7532f2e9bac4f5d247ca12e0f53320d0a6e205dcd3a1e9e199c8d90d16426cc72060175b779f7de91ae16475d750d0a6720b62a0b4b00f7d31388b33cae14e14eca3dcf7dc05e387525a1cc57f5487d49230d0a7320775879199c3fe2b076be7853626f8ffe3b37117cd9df45307e3bd40d0a2e20fb4c5d75432834b6bd2a8470fc28d07872f48fed69c952c161e78d92b60d0a2020f30a96881a9f8578430ffe17198f61b19cb6c0d61eadf947422dc17116fb0d0a4a20705c2c50d222e0f0708be5292433ccdcc16facbc63298523e06a0d0a75209749d4125822a56a992e6f5ec0c552439fc2e9f2adb1ee82359d110d0a73207590a638f70ae3b506f1f32ad76bed42d978a47b6b18bf044389c3a82e0879c50d0a7420b985b62542b9d3e4407c96840957e36a27e1e0990a63dfed6d0d0a2020b2cfba0c9408786d9eecd33897a2efe1d3ce7310630d01c326dc041bfc4ef4c0e9650d0a6b20db3c72d9c54a158d0f1ca934928ed76911c7c46ceaf94cf4ba24fd9579482aba98160d0a6520415f99b810ce393c53f0576ccb3a9636b29e7b01a6e258d28d885ea9330568e486db0d0a6520b9e74020f8363590ddb460084a67efe6eab1bab95a33180b0aebe5cfe6f77353b0780d0a7020f729a94c445f285cf40dc3c8276325ce6eeba334e42e05c376cc230448c72fb8cd0f0d0a202036249a76565ab7b261fb1af10ac8db6380dd6d146116acef6302e40ad309b8f2973ab871820d0a65203c2af0303b49f5b8013486e63805c16af5cbe8b1a574bb0d0a782050069303613b18697460a67772278c68c7caa60c3a169ef902f42b299118f95ac90d0a6120375c5338d58fc253b045a426a8c15ae4cfe14d7ad4f72a7be90332536712c259fe6777d60d0a6d20cd106f121b002f9ee47af6b37f6befbcdc93093ac6516f43e6c280fdde30941fe8cbd37e0d0a6920cebeb84dc4505d5a811722b5af2d0609b888cf8adc8e402f8a7548ae2717694177f8fdd40d0a6e20d8cf4836f492ca7f8c8cfc43a6f6081ee0a2d9e59a4a3b90ee6ad37be7f2e2b0ad90ec600d0a692075dc3ce64ef0cb4913e9167fd54b8ecc37eaf5f56c8b079945873eddd60d0a6e206b037f2573baa6c8687aee0bd2fb6d547ed3d559049ed04c64151184db0d0a6720b419249d4614a01a57524e2b163ac9894c524d7abead0ad5e00b395fbe0d0a2020e72499b2b9ad2575c7429be917246d4c8c41d27cd8ffe37c47987a445a0d0a65202f4f07ee4d49d554f3e75180b0f8c99ea6e6074df497a0a78c628fb8104b5cbfb20ce20d0a7620d5ce376f1995cca71984202c6ff0d58f7b27354234dee2c2587b4f6fb4beff43a9e26c290d0a652044a84169c41a31436886ed52cefd2b2e09eef40671adf319aa50f05d76fc79eeddd98b550d0a72202a4ba5beb4aba03e5bd7dabef1e75cba34bb5739e1deff4db50714e34feb33ace1eb3e340d0a7920cab3c3192a3236c0265f1b2b02d50df6c80ca1c15a096749f478b3b69a5b56e8b4c75eb70d0a20205cbaab4ffda32a87348bf3d85f168ad49171edb42a4bc5d8ccbb2812e2699c9b20a80b440d0a6c20937dbc6457ad6302e87945148cf96df25b01c042c98a8f7c911b616de1c9280bdeb064bb5e0d0a6f2096153950a73c0dc0c9956c0046d8422a41a6d2305b2e4947877eb1f3ac4d8a8f26a262ae0e0d0a7720e6a03e3d2cae6fc6200e53a0d4d5c0b0940737aceb48e6f7656db91671360d0a2020a8e8be9c80d64a1c12f01f591763f16fe1d94057dc01a0e23fa20d0a6220c9c050dd5f91c2bdbc4c188092d603730e6a7b729380bef8aaed7ade46b227a0c18d0d0a6920ebbf9670981bbb142957ae40a1dec346201908a1cfc28178b036ac8106a2a6ff81dcf0f7022c0d0a642085a7defa9a767cde5e1b2e9b6b52f036404675bbee155e86f09efa9f768e20c425b7ee1d90b00d0a2020028887e96da15a4529efdb2e203788196ddb821f2d44f5afac1cc00f6cb39226bf15091c9b890d0a71209a592827dbb280c2cb90df58e318ac0a183f0f6ef54f5687ce3fbe72992d996ee766b490133d0d0a7520b8aeeb47e68d9e5edcbe7652c21f1a2e2960392a61656397f0fb0d9f6d1d84049b6e0c091a7a0d0a6f2024624a82df9ad6a43434dc7510d3aba86dcfb98dc8888051eda7c92639d3c027920d0a742039d54073eb456a2c3b4984d3ae8d72560247b4d041902fe70e9da0e045cb80270d0a6520ff501dc22e9344f07fc5f7f4a698f82fc1672593365bd95d620ca9436fd81908a37d12f2c862270d0a6420ef494b5976d137e30d5fffa04705f470f48236ef3e0ea8446be6f8bc46ad9f076493dad0dc4fc1e20d0a20201e3aea24f0ab348f8c0513078e0ff81937678bf61595b5efc3a96e559d73541805da9d82d32b76d80d0a66209f400278ddd1f549e7e55e24848252393f0e66eaad40a59afe302efdc971e3d23ffc0e262debd6430d0a6f20028595d51f8b68f2ef83ce2cc8900d6346957b84caa3790981f852daa01d0d0a722037a2a4b7b5f6560384c5ae4271ca953316830481497f215d5f584d1370dd0d0a2020b4cbb202c5a9606050b8e064a4db8f69d76c3bbb41ec4ce53ed9625ef5cc0d0a7a20a83eab5609873ca3614858f9fcf642b945a85944a0248f31839e4a5f752e0d0a69200dd663a24042f0a6a6618b7b3f1d4a55272712d7dee63c22ce05df489428421c0106de0d0a6e2070ac1208aaf2ebed0819e8cca4daf7d623eab02132ab246522eec2280d0a6320d670756672aa7826ca4b637d403806bcdf318e6fae0c263d604e0d0a202085e153ba77648acfdc241096ecbe085932da2d3f540a8f49487216d483d86ae791ee5762020d0a652057dbcfad9c4e6f45cb6aca49bfb8afe9ec89c1af2133a00a362456fc9034adaffb95c829ba0d0a7420a7d20fd33af595b94d5616ef95bc08cfaf8f2ced5734080b57e132599d7f1d39ecae014c260d0a63203e2864fc552f48c4cf532630fe186f67ed5fbe644c10a722a014371dc44607bc8b9476d0630d0a682090db3f64fcf979f22fbf341a53ba241fc311c95dfd27aec3abc7b173aca6d6269dcb0489100d0a692031709c8432a44e1f158fdbbe7b328d31e19e9357ad63f032ae8668dfba741f0d0a6e20488e0f642668a35505017f8190b7e53d1ff320ebf19bd44dfae5dc9a7404930d0a6720de728173e284bd4618d916a30ec7084a0282e85fe32f98480d0a7320ed2b5cf2e589a14f0b4d9316e882c1d449cb46ee4e8a5542a96df79ed2c0e70d0a2e20be7c05bd4057c32eb1770df804f83e7c0f58421a0c367b7bd67e5f88d8ab730d0a2020a7cddc1c77ce5d83ee6af31befb5c5f4ae737ed9ad6445d20d0a4a20d48e8e8a4659250cdb50be64b2c7f710232e7e9df8620a41dfbeaf485f34f8970d0a7520f8b5fe2a8f5264a3c3a397d74dbd95cb51be7ff107e4c4641db7ca0e55abacca0d0a7320077fde251da7ec82e1f5ce6a4a9d6548d87316170a909c01cf4bbe1260b6a5a40d0a7420925c5ceed7d521a7841d140ad73e199ee437fb9426b3e0b0da099434d7fe957deee67f726c9f052d0d0a2020332781d61f01f6e6874f88c6135b4aa8db2d6abfef53638c065ef056061afe58389ea9000334d2130d0a6b20dafd87cb69dda55ab7d32c1133f8e1545359fca44a65a4d2fbf20e0d0a6520ff4ae7a28a5ed011c877bb0b175ea87dd3836d107d823e3385aad19f4e0d0a652016054f393dbb34ff565e188a64d400ba670a5110d8770d968df2720730b79153b07236eaf2b2df72a23802616dfc31696051edf2a7e602d3b466dab1190cf5bf869e0ceff0280d0d0a5420f69e6b0a456124addb2cf41806cc9d8a1180cf082ed0990d0a68204292ebee557183698938fcaae5b83a1764c38e76e9e093bb6c5b04b4902c945c55df64937da01e133549bb496aa04191cd3a9d66bd71a5e2da79657af875ebf7508146f47789836cf1a823b63cf314c295799f11430287f9d6c72df4f75b35fe1821397770ecb7c62a28ea0d0a65208c4ea4caf3776d82c6fdec9eacfcc6e7ea62639d0f71d6298cf233f92930aaa0c6efa85ecd563ca9da6f24db43f71669fd2a9dc30cda309933b569369ac51fa462badf760d0a202045c24f0e039f0f6573d84589510a36a00cab6fa1282c09c905d0bed077bc783f4d42d00cccce6cc4516f621e28d70e50e21ab052891ad25eea6eeede07f82a3c71bdb3bd147aaab617a6773542bb247a89fa01717cd2754ebba640da94964d6c521ed65aa1e4d6b7d63a53f1fe0141fb5efa5b1a3700d9c78be08c5fa7a6457a913e07f51e686b59c1518071b79d58b46de5e1a6039ce3965ef4132ce90865160d0a6d2029c38412a72b52bfa82fdd33b56b4848735d96cae2eb409c2b7b58dfada1766b7068178dbcc71e9fd96877e02452e4b1f774da425bafe6f89b7ea5684f3a2905f2ca3c5d98ccc3891420f4ead0d985ef232b880fda400151d484d86b6e0ca41938e3455d14e797ab2a66060a0838f51d6025020d4414d939d13418f0951eca9802f11ab7da52ef7474f515bfe73f578edcc1ad33562d05b7cc11517fe238556b0809c9af560938dbed27b6ccf33ba4e3f973e53292c8742999b955e0c9d6102f0d0a61204d8d9924fca6d40b7b9c35b9adb0b41dc10a4f750a36f1fa13aa8bcc624d2bc0a6e391a2b8541f5976bd95dca3dcbdbf0c72af08cc632efa811bc7945ca6073cd236af52aef868bae1f521e0d0633f6e813b59ed2479a8b9d748ccdab92cd5f92f1ceef0e96d6b84f4593168b750b73dafd419d087c62355bad1965be357d8bfc5275ebf360565a8edfcaf28e26ed7605b146a27d4594ef8f6f66e1e146679f484b4e3a40faeb10893db86c810a62dc3241612720e49edc5de5257780d0a69200b2379c14c4a8ae0c4a18aeaf1394b6fb6beae15d7ced918e24632482c9ce8a6a2b3b5c93b75fb3f66995a865d1445473dae7f6b6c500bb3bc48fd5cb02f2e9057005c82d1fe9faf70c51d2f994102ed725ab12512dd159ff947cd7113f2b048a6aecc846a3b2f43ff4c0b9e0fef72026196e3beffd11aa00922aed7e4567d22326a8a42c915aec64c85846f624dd227908d5b51d60c2f07dd720d4bceae7241729ed797b9bdb3c6f49058c1713612886def731a2e3c8e024705707937a19bcbf4f19e6cbab387f03ea32be529afb285706aca103a0d0a6e2052d47eeb2892d03c2a271f5c0653c010fa4e0188739295b39b2dc4ff05414f68068c109a988a506ecd91b4e9212797bb0d0a2020501ec10488391a2f7579465405dfca54b3c9e017ceeb6a3b12c25bd198afdbe88409e807df692d5955dab71b044fa8e9137e62ba4b7bfd9b2eeca5afe3f9ad28246b74b006ab41f590365155dd41c0656c4a4c8a50837b2d55996f60a11b850d0a61205b433512163a92c04c0012c2062ce734bca8dfc56096f34fe215786e28b897423a24dd6c3ab9550140c814b1c1ebb1b208c6d5c37e6888546af8cbe0f6b968c2c12dcff5404f8760614189fb731d55a89c2e7c1f24d16e4f4cb1a11235280d0a6420b2535c884be264b645c6c83af14749bf58372d5eec3a10f2e9f84ffd8f130ec429cc0f0d68309a771e9846f8ee78bb586c6478064d65155458a77d9bb8e6b75a727c9fa109955da6541950d1cd79873879acc79879266f64aba43f5a5d5e9cfc69bc400e173e206c33b1f206112701c57326d1e79def9c03f80d0a7620fa1fd7dfe04cb709fc4da7e35032e4d32db2140c8caddbc28c8498d840bab6b47c42ed8141a599bd95e5d19e5c94a959b1f17faefeac50f09952306fedd5a197d9990dd9b40d0a6120a6a313f738bddc30c0a1b117153f685258a87b83c798b5758ad94d4b2165da94ace23605ec7e5fa7341c50d3987226b7d5b66932ac28af6569c64b9cb8c495d2c5a00218cb9944962e0d0a6e202320bf2038fd3a186b6724f4dd1d5f6a3d592c00e70cd24a999c15703c9f52d0bd8b613428376e16f86d69541a27d6670d0a7420ff870c92b8e58e12f8bb83fdcc2984eb7c339c19145c5fbbf002386dd3f65f81254f31fb8635578b79266b08391191249c93e2ceac0d0a61209be4f9b198830b431b2657b211b470e2c5c869f2af5dec7363279024ed7795a7fa93f25d8aebc395dd3178b30ec3f00013bf0d0a6720f2fe0b0e82b8731889a4f1574470989c6125e932e1a6617045b6b36a4555136d32e389301b6a31d04c4ce58c83dbc881f70376b66ba213afd65e609a3e2985907e7ec38cd42fe431f84e2473492ee38d9331101cdf9f58cf7066413059cae726ea13e021ed660d0a6520e2e86c939cc58cbdc7f45f5597d1efa2a17587d06c95bcfa96d2ee0a0d72f0c7b9a6b45eee1da7cd1319bf8471d2e90d0a7320ff3bbf9a4d7ed10415a353c252e8a762687439500b2d13c0b0c7d04934332404163b1d89264f340bf1ba2f6adc50f8e5aa2c6a9c3fcf2bb2a55ec888ca10b8931b782eefc957c86b33ed68854ce4265f1ddcf2123c6109450ae17f5038d88531ff601db30d0a20202f95dfca5f7e4b8854fe2227100e2b91e80595dc147e8e095e9adf380fdc70e240e90fd7fa27c62c9e0b386ab458dcf4fce9197f6c22ebb1c342397e0eba1f82bd23b8ffc7e1d468e5dfd664b455dd2dc468b04c787dc725f11d29a41db99d8c003f873c01bc463b8b515298f3840d9299a5b257c2e35bf1bbd995cf004b54ecab22a41552c07117d70d0a6f2011b08bdaed6101ef6d0541d189e0ed88d188840db164d9e58e464ed904970ca81fb89b401a5ae830ec595bd7ad8f13e7a9400e3730ee72b8a5748ba72a090780fde5cbcee46b1c20d93190e51e4936514aa12b2f6086180f110d0a662053aa125db3464ae890fbd4843177c43d93460be33a42bedd50b214f6cb4371176c86209fdc3b9795e74f3b350389538db53c8a908db5ac0d6293752e80d49e935ee8dee4bdb66dbf2d844cb22f62451d3ce669e2623bc7e3a039aeea8cfc86f9169721f6929b6346ae14336abd78841c182d26e160e65d0d0a2020bfbc006e4f845c4f2fcf482e4b28e09fd20e2fee0855d6f6448d9362fcd8f896c8d7badda6d5551f3beea144619b5114fcd127b90a6c348bff10f5a0d7989ddcadf40211557114da12d742bff155ae56c0374ee92d2a1f5ae0e61c9f74fc7c62915b1d289687b6be28ac3ff81275ad56ec080520642f310ca9d8fde025a33ddb021a40b44a0d0a6120d5eb639120cb3b060782a0e95b5fea2d7354d6ffa0044df25a0b7e1ffc5693a2b472c762937b12ed5a93a61557afd2f75d43bff12f88801b23ba424ace821d0d0a202050084cf2ab7a590434882bc714cbc1d254175c60ee807f4b80302a948a720bb787d8d82c7747e6420a84e0fa62cc528a70c182802d293c3872275559661852b533e336805a0ddbd98ea554188eb529d2395641fe1c6ddd9fa9076e0fb3b91b8bc6a0457f05ac678ef32d24d6fac7461aca7d3a32f65457c34395a93fc87dc1b4336007f60e264400e76a93154928b65a6698f824d9eb596061fb1e5ffbdf2a5b52e3fcdd84cd735ef7591691d2db518d010d0a6420276acc70e256104396fe961964d62830e6aaee75da7ae9a71e26a264c26df317644afc91920d46b146bbe440e7db0dc7bcac65a5c16ace7a7ff23e37045b36f9d83d6a46457c4b30f5d365a274e35aad051873138ef50861d18c2d9eb5fb294f3a85d2c2b483e7557cb2b7f2f7ffbd4a651b5cddd277ec66f5404e87c2fad4e8c442f9c4c00d0a6920ab28736f70f02d27ee108fe3e752c846dfec15ee4e8d7b73278d96141f625dd76f0fc148ef06f9b4ae4ed971a255dcf8ecf0260a64586d781b25836a620dddf7817a773dd8484f7263564c48b091ffaf9d7f52e1c1d20d0a6720729021fa1722d3b929b88b76b787577c4eb52e5f704649053763dbbea06cb0036a0cc70514ebcbbb4a595380f7ab7a8211ed0cb3430a1230d896e0219fe9087d0c6c5e94da4bba82ddbd012291bcfd1b3f8f9dbd85a0a646952d24a64dc1ec3d0cc1cfcf0d0a6920b562ff2484e0f03dc0754dcbd4ad92cabcb3056ea49b639a76df7fe06dd4d8d20236b7001d9b398ee5e96627d39e45f8cf29b2a4721e50880de18af3871a6801020d0a7420ba5afa2d563accb973b7b5b5e9dbec290678a21ad7a75f13ed0e1089f129cd4b788f262242c703df0f7dcc6748404647e026411143e8f08d0ad5742c7941a9c9a40d0a6120ed61c4724be086144cd4394127879f18f6c3ae2a1517a18745a567d4df32a9fa0abb2d2377b69cda25eedc22bce867e7332502658cb298e481b7ddbff2f32ee884540d0a6c20afc1d7dcb2a7473bf006ac50f8788def7d188ff00c9e0360baa6245d73ad42db74a2706558bea5733707a718cd550c38d4c5dbc4c39543ad5bb1e1a58d5049d551a5c11279ec0d0ad893162ac5c51a74c2aa410f25b3feec0dfce33dc9366ffd3c4f47f6bcb8195bab6a4212b9532f973dee1d720a6f390478167d3bfa8601960fe0f453e08cfbf00d0a202038f7859cb5cc0bb441658695df18d5109589d4423e0ef71a00be32ca90fc255197848065d87c566caa01446bb4f4c65a523f8fec878f72106d9505800c028818bc0c099f9f1755728a3a29ae6b7371b21011d5ac6a0e2ed6a4ee5a559433f9ccbe300d2eb0dd3a9fa602d5a7726ab1df0b917ab399829469938d98bd0cc0d3e82a6c898d61e5a67b04abc2e324031738db2280727242a1a3d8b383743a3da83d94e1a5a14a8ffb4386d900be9868150b1f528f0002b8006f20423ce5b2c6aca801a8507322e5171dd9d3996f6f88275306f6706b70f210f45fa76043ba1af53f0e09f28e77d2db6aa1aaade541611bf9d1b612c89cf9a529e48f9229f850735c542f414c388d54f605ecc00b582f30c6df0d0a64207918079bd8033c5c6d88858dc110c6ddcdc4d515f9961c1a9f54a5b653eb1b4640b5cc2a7af730f4db53be1f8ecaa4d7c992cfa79172f8601625a79ca7ca309593bae51037ce07ce87044bd4c152414be99bb4116c0d0a6120c926c4b086ef2dff3c38b15ea858c758ae3dd38dea8d1fac44270fa7354ccf2708f2b8ec1d9a93f446e64c466f371aea6cf60c298a0a5bb4c888b01d33b6d4b2ac7508ae2c591ed624618151d589436777c19183f0e95abfd92c927a266e4757764568d716826d2c6a7d260ebb3ce4817f7c5020596ef54469a6a42fbb0d5046d4a333a00a763d99e2ee37965b3505ddbe0d0a74208e29ab773e3d625ec81ab4acd1b46a6a7cadd8d6ffa6660895bc825f8594063e5ca6bbb33eeb90698c3ce1d826b81fd361f6e6616c516fc8966cbc0134dce50bffd9503438bf81328704d9ad1c884ed223bb8f790c8393f978aa69c291e5035c9d9aa548772a8d012b7f858600c70d0a6120d50c8e685776c6c46f551900090a66a26ca0d1daf761ac6b96215dcc4d850c134d2fcd13f500f9e22a4695bc8d819ae8ee078dc70d42a2b6d10b5e2d92474ebfac22748d49f59ebeea6928cba19942cd1cc85a57b146ebdc50cb1c2a778ec08d314e94e90c2701c4ccd931490d0a2020c9398326471525c772bd912fe207caa074ee330f83c1e6f76290c70a98b29ea35b49b743dfb6ca74a31d65c4c42b0fbff46027941542885b22ca577e65238bb91c663c55e74007df616fa00d0a7320158b710b661e877329726b8c71527e3e28e52bf13f2e25f176ab5bc34f228ca4ed007c8c80adb5b4aaa80868cc3bd07132b4e88d15fa6e26c6b26e3d73753447accf34c3400d0a742048f70c877e5040fa8798518637ba040cc17effe536ca576cf71f7ed2f69365a980052d57772af07d48c551fc328729e8b5764a9331eeaea9d562c09b2f709fc372eaac3a874c9b4a9869f865ffd6b094147ff1214e3f7111ff408dd4eef6b28b3eafc5b5289083341a0b8987ff0e527ee7487a95ab3800ccf3efb2be480bb726d61e550d0a722062cc68235cb0ccb2103491922cf5cf1198c62fabb39507932ce4adc3bb98e129616027b7d7a562d6a89605c7fec45423515211da7426abcadef59c16cef33215a2ae407623b1969597bc310080cd0d0a652052946808d22f61742b7f8f277dcac79c497e655f8512203f56f054bc0db2e642ad43a1385c717099d9ec60160d0a612075862a576494ff79ba653eec778ad0cf0cb071ed87b7acbafea90c113536a3cca3c99f8b17c997960a5c8defda1d972cd21b46e554f96bad17cc22f42736a00d0a6d200184707d3aa2901b59336c71276dbbd599db6d5b3a4849300cfed57cf370be84c240114e1ec05d620a6b8e98942985575e0f5bf27a1b904f9b99a40d875e1797d1f3e54c13ef1b88970d0a20204956b8172c834398f56760c11531331fb876a0f1a5a3e3bd29a76bc26a16370d8deb3ad404c404544e752b046f2a4787386ccd0d0a6120a99b45f0f43139aa5e003337b4d211e0840b57fd4af34474247494dd02f8441d6c7ada218bc380450b3fb9abf5dcaeb4613eba492ab55d854a165027f6ff35ef7446d5a886605d57fd7987993422a5eaa00d0a722024bfde2ccbad9d06af42a88a77bb97c490d4ea880c9284b014f9ccb55a442c301b42abf2878780cef0096d021c323273f9ca91da60549e8a93f99b12b20c578f7250d29a545c674a73b8b7860d0a652032bcb294bb63f24cf1e31bb163ebc4cdaea3586a2d915e9502d732c25c2fe738c4456c77d1f4530c1613bd7595d3583bc971731c39d0924d7887ea75ec4848e49fa8afe410ff02e9f751ef1234b3414b0f8a4aab4ab6859418b0c6919109fc8a8583ac1b89afa01ab6536b9cb3a5fe37b8bd930fc34365580fe15e73d81df053016cbc620d0a202021fadd888abb83894fbb84707e333a6af2447302c3ace25d1eb8cc379a705ba8add551815117bd632983bd4f43c694768e661da35e88c29c688445c91652c1d9ffaa9f3658df567332c7c531a0074a56ee635c74a8e1db9fea90af489f03f90d0a63208488f03d3eb6c514fa3d94066ab684f260cca5506f4d7f99c599536bb5c242f38ed97f209c1b52845872249d80e337c73dec051137bf0e2741a4d4a4af4dd387d22d69e2f7cc1cc91f6ba1d334b8a8923c67491d69f60460c8b0791a314fa5dfc25c1b54c031095a8234b36589d0a7ad317952f78857cf2323e7cd53ff61dac3e7d8a00bd9e6c3333009e22da75410121a62c9945e91655bda6dd76eb1acc00d0a6c200415be4058093de9aa2316cceed4e1e31f33b352df0f3a5665e4b82a18ed60711eeb3a0ca53a942ace3aaafaee9ec442cd4549c0779dbb354a10c3882bed259c749b268e7028d21fbc13bf9464541edd8d7c960617303c1648dc28e63e665a6671885a136b67fdf2ba67f3a50e806d9a53f0ccbb7f7225aaad5838f4d4f30d0a61207e720f01fc9c5f0fa38d35a1063bfd5127fb36de943cc5d0e3cbcd3d617ba56369e49f49bb240cd65bd20894e7bc3115035a2009f5d3ac1efef14a4ba758d2f78854eb2ae878a4c8be93583f800f49238ce507c75d51a708ab4484f765ba416571abc98fb038e03556aa19cb30ccaf803ae0332eef25df23eb4306452a4e92ef530b4968ab7e1f3b0d0a7220cb744f6b008094d69881af23c7e33d3506a3405a20487d17aa51a679cf734f91aea14a5a7c1a0337878dc28d06130f795d52822f715d5986f0126a0d0a692024f94ea80b80b9fbc33778f8bc82cb60a5c6892edb8102041ab3ea236692e1583709f096f18a4a1e8e8e534ba1c1908a5ccdfb588e080a239212eeff33ca0763a0183be73ea3d8bb9d62303e7bf49fbf593d719863f52d09cd85a90d0a74208d3ebe4fddd8dd9979094c906c85a5a96cb240e5be6c36a9e3de5768c0dbede0707ad6ea1df5c8f907f1d65982a3b9b8d1c20ac781c2f9198dcee68bfa77530d0a79200c3ab52318b338558f737e0a14283d4a08c2c0e9745f46cb57f1d7e68057543175dbeccaab8de82a8983fc48231a97f761edff290046a58dcfa5b78d912702778b6300954f5500f2544c48654170300f82be7254dc152b2c0d0a2c2031804cffee53e36ef173067f30170bf95a73096321d91ff86b303303b8875394d480710dbf8269e74adb8830380c53aea2caa50039b6a3cbc10bfaed05bd67b186d9c3ebcdcb619a571c6504ac3b2a29439fdc8f0d0a2020c6699929db1bb745c643eff9f51e8f65ec5f211c70e713228df39295dbe2ca9c2efecaab338d77095a081ace85fc72cb444e8e0d9fc1ae30fab92dcef43e8445f108eddb1b0d0a7220ecf1826f5d96c901c62726d9e141eeff8a2a410dab110a6286aaa706a5f53ec1f0168d69f3e6168ca9527cd3f2068abb5138c96540981bfde3a2581e7fd2e2b273241e2f44b4d6e40d0a6520d00509576abd328e2e715698997ab82b6070fbc94ce9d17921d57ad65684f5bdff26ff0d7e10b3a9728c3588f2d7f4975d83d852133b1dbc21ce46c9a1085d6e805a23070d0a6120ae79995e1ca0a1a0008d34a50b9f28bbb37ec71b32bce14bb0af83a919abe1fafb54c24e42800b8046e13f909ea588a3336a296cd7171bd9aa0d0a642017ea3593bcd590f325779a69e597a4c7ab9b8030ee4714578470a4b7085e8dbae56031b94cef069855a3a4b86d5965ac1e1f1fd81c9d481e3cddeaaf1d3e2d2a12b39e0de7417f26090d0a61202ad7433c150e0613d7d5067ca205502505663f5bf781037e42ea9c649962225173bb20819df4b984205ad6359ce4d7e7937c4a1fae3859a5c13decdff428a794800fb0fdec62467e0d0a6220ce16e26b0aad61c694c26178a2cc086c249b609595ac2834233cb27e92c9c7146f44ca4e557533bf99ca64a80d0a69200202da67e274a694c6202b46d601e79ed784bfa7c3d068ba44d23a6c4821d659e9346760c73cc2a8bd502ebb6b3274d5cd2d0d0a6c20e87a875e9e430ca30e536d2db39f665f9b07cfcfb7a64456e7c72c5bc49893fe86a29be8ff769cdc0d1f8dc1a366fc407ba65d1222e6d4e316d853c02770d2e7a7d71204827690429c0facd704145d445206b597a503c4c77181e2e05d82b92b2d9f7fadd14af71ffa2eb684eac3b6596e30c9e9a5d855a6d66ff074651ca4d411ea97756338e5f7171a12497fc9b5e023a88723fd17fae998be0ddbd3960d0a69201048b3cc3544e7ac0fc23ecb356de1a4369050c5f0e0b20b127fa3cfd99e4f64ba775987a6c5aba8cf032ec1dda95ef0758f81e5b4c19e252285b62b89e4077c033a90fd5cadb5d9515de054d94a941d8cbe15d8ba19b7ee99c7f21ce7d080e010aa7ea3590a0b19320e0eb3ee52466d0d0a74201c64f425bb2169df311a2f5597270edf99ca9649e0e7b309d11a30647342f61aaf5293858da0bf69b3279470faf7267088b9914ce3dfe9b24eb9196f0f18cc91b9c3559555c48510971ffe8a7b8ef129a01829d8dce55afd03b470e6ab06e89b0d0a79209083a1c2bdf8e16aa3165c310cfbbecaf18b5fa1eba09f16cc06358001374bb3b3ee06af037d43421e99a19d33ba4088ba999c8cd207a74c737bf32490902b7730ce78b4ca848dc2534277781312298eb0e2f2887747195363b57fb951429bcd95888ffce4359a5cb9ae6a8b7ecd6ee67a4935974ced934d36d52333553cd08c3570c3f68c1da63a495464ebdb1f0d0a202003e91a62346717298bff3cbdf1ecc18a9e53867aeb9b9f19106fc20b843836e419e299f98a3c9ce0d93084d90d7aa8cdc81fa25766a17b659aa2e52985ab19c99322483d840c04d6c2d029195c235af6fe0771e7df0899b84968a861e0f150fd62b31f02a8891464fb126177223c0c93b27d15d6c70d0a6120252fbc5de63dc9375766a4b2073005eadf1995705bfb3d7de706ce838e1540ebb4a25c989990f0b41ffa7909f10fe3e0d90f99082543bd7341d812a413a6bd015bf2ca372f9070f5e18d7e009847e3cf514bc9abefb147567c2703370d0a6e2020a8d4ac234409caa1c9d598dd328e229bd10365903a7504cd8997b23dcd06e503468ef2115e7ba397ddcc82ad81d267a8ed08ca80ca7b7b3cc1a3f4ca12d572d9e4a32c2ad17550efd3ce38e840bf1dd736c25bbf8ae87dad30018040bf4bc6575b26b2775b28d7d722d5f293bc856cfd437bcec2023907e8dba2f02ae69261ecc065397d1768acfea754bd351e55d3cbf3cd3b76271636e173359da81b0aa4e7b1716e2321c49a800ee30a3537533cec680c3030292128152da97e2c9757834c1c04fb21152fe267803685abca8839bd9b5dc81527b90d0a642088b4640b8a707a89ac671452912fbe5cab38fd866fc1fceea9232f739bdc46eb3123fde09cf62d45c8bafebed615057d1d6c74eaa8ff08e2bc7da50dd88462e13986493974fbb6446ea692e364208675f8f2ab161c73469dd7f60d0a2020fdd0622da8333890bcfad4720eed78eac5861fbcf77b270595c1e30d49d86599910d7fc96a369a14ec23aa1ea6c4f6431175fe792ee93e48f6c279dc3aa3152113b0c16134872cb1c1a7e9460d0a652096e05b928c62d916ace0271d7328a119fe165496ca0cfb3ed544864093cfcd48e53ad5c2ebfd70fa4dc9269f2087a43052f2e93fb122d9d4fc0dad4e6c98c8bc9d40831497b059fbc98b9fb37314ab6589c45a4edab176f362cc6ce5caa30d0a61201b2067c0706ade699715ae36027e3812c721b10a3c54d05af56f6f6c9136e8cab69b1d268649baa4f97ed3cea1ae8b96400d797cb9e391931189c607a9f653b10058773a3c4a7f4ba5af600c4ded0d0a7320080bbef2729d0dd4bdaca4c6f133545062f55e3abd13c04924dcd0614e7bdd1c99eac038a1f0ae7fa0789b74a80d0a652025a9ba65e4484c4ca9261b30a5d0d2c9581ecde45ee60fe6819920556e46d449d281acf686d4bf3ee16091d3b3d5e4dbe82307044006938d43b84e4bdfa4c8746e1ad97dcc9ae61c95b3bbb47fc4ccd06ee15c04f0091998b1a176d8c8181a435b05465469d4d1334aa28af892d28569afe26c02228a52a59a0bed56d76c87446fe27139d732d993e487df38e40d0a20205d1c4ae4d90b7576d6f5dfd6cf58a2b23aba655c320cf8ab28506e3b0277f054cd77ef6540b5f09bfe59e8a52d4c2432db40b23dd93b506c897249f08488994985b720eeb7458e268366eeb89b2f9c7b457a80cc99b0c91788c3712579e04b874eff0f41bf0d0a6f20cecf59d0237445adef1e61090a1c63533780e25f252998333986c0a7f44eb262c7767f28fc41a51856b360e724973c3f0a8c70b4c24e6933eecb17240a1ca579e803391ccd01a304c17595e27df95a8251d1a57a467ea7eb1ea6117d660d0a66202dedf71f7a6457cca206d9d9f8198119acaedc29a521ea4a25509ac49ebb93cb17ed252097ea4083a01907175923d0616bcbd57f31fed51c0b68534f06840707265caf28798a70fb9f8eb82bb703ebdcceaa210eacacb6f847bcfd1420ee66a87a8c251e00dec80ea4183c1cbb14a430a97fcc6f45cd091d9e76b4bedb4660c476c8748a150cef520d0a2020687b4b93f6c1a7361ae79e082698197fe451fcb7c3e08b7cd645b82a8b7d2464e29a69f95b476c92fabf4b9aecf1a305dd94b90d1fc71b1632506572eb2a7209ea4b10fb3e55ef63f79b947980d02cc219de590e0f1d171a88cfdaa8213868cdeafb6b2c7dc5f8974c8039fc841ae34de1108966a0a6f33273018d307d81ccb3e650509fb60d0a752068e1658613d75b5c49086484aa8f476276daa4cf09ca2d2eec45a333340cd3a3aa712ef4b4e82de51e1aeeb207687a3aec203dc2af65e610010038ba92579ac4c61f36e3e5d3a914ff6befce08ad736486b87501b6f0b5d4d9669da9e829bdf6220d0a6e206c46d50506eac42ad6b3196d0d0e04ab75df8bb59984fdede47f75cb94a96497502a7ab6ce82175b56598bf7ebdef99680eeebee4c9cbd9cd1dbc1ba6f682ac8891d84d068453dd95a32d1f8ee714e9fe588890687ee061ae65cdbff7e8bb6947c8e63c5376e8e0673c7a5aa9e5315c952610a32a7ffe6e3260d0a642086a9ad508b454d43295a12c340b3839c5c19061fd89e245acd14492ad55df9f27214907a5a2fba2932fa1023ee8fe2edef76c89642ee24aaf2e9048039eaafb17e549de90586848ae39ba3095c9e75583b1a45fd8cbd46606be46e7e210d0a6520d5cbc5f346e18c96491593531b24894075e56e80a05ecfebe0d1d35dcc0c587a4dd451b73d9740ecd10794be5b371ea9d23639fd756bc7578c064e73bda35d2faf544cc3602f0071ae637bf000b73b28e36127465780f78de0c9d9e247864b66c94e840d0a7220b383911d102ca8b133cf60788955143b1a22ba5cd4aeadac73f40776e5e8543138db4f5b0c59e9d5896d12f8c1a139f0ddaa8c4536d66274c55d5519590d0a73205c7f46b8618dc52191ccd43a56ec9cbfbb35345acc94b172c888d79b7b967bb9ab7df03f7f2242a6670b50fbc8ffb4270b772978ecdfb6554242b34d13295aa433dccf35ceb9ae1bcfcb9b0eb701393cf2c2f4870d0a74205e256914c56201bade90466be9a34e8fb97025e744f29e9f661029af0037ec83208571ae9d13c9666cda67692fa88a5d89ecc934e346760f96b9f081b03a8134980e6a60761224df65b7944e538eefba0d0a6120157b667be8e539a57b7a29dad22480022634a628d5bc33d6bf91186ee569af513cf20228187ebdea378e780498e0e0f4d6f632c7c0b0e57910d0c955653de703e65b9ba0d70d0a6e2010dd198922365136f8c873a18a504077cc2c5ec6448c8f5bdc89907f0df22ac6375c84fd07936a02032874ef78bda9c29706131e1bacecadf889139a98965a7b787b492b50f8b70d0a6420b792faa3ff43a09849069c6a22dcf047b34f696e790483a88b0ca602b91ebb172a1ec56c4a3aef090a58f5859fc5a4c91fa7d9eccf7a228fa6899a17572e3d6e1db1ed51ed018529f94e28e26ee194896d95b52776f228fa59c1365999c6d33fe3d2ecc5f9b96545f2d869e63d599548142d565612c06a49e0c9a568a49abb22825038add6260e8d97dd80cc6717e59700f038be4afc7970b5ed765cb1efee6579755c4cbd0d0a692028ff62d0979d36cdad5432ef66900a6ae16c5cb3d91191ec142d36f8c4fb51ddc1b3700f249ce50a6a85e3f1f15f986de69c6e87ae9b0d0a6e20a46063cc6f01188ac466ae7495560199061bc621b53ff30c321c28c14874f7f796a2913ae36b7ddba7bf759419b3cebfea71bc8ad5bb9d65b9ba06c21400f844172300c8dad123fad55fa64809e61ce05b22b51a7f4467bc55eab3e7f958730a2bb6c04af4a49f606faf0aca8ecaf4fb9cf1c85c0fd99e8b53671f0ed8f78d95b933b496e930bf9e314a38fad611ea418007326b537de3ea7d316a8893950d0a6720a6aa83643d6fc8e800d7c94cf2783123de5fbb187ce581a87d1a357b9aaa94641df0334d28fc54dada438913ce69e7da968e5f4ac240b6e915a907d770b3118a9ffb18bb5a5edd39b31e6f27732a3b1556daee5fca110ac3436116483f31e5dc4d59aad60120fb9e20e21159ae626c1b0f87025e6e64360d0a2e202df8d388f4a98eda8dfd74c40b4ae1b3573bf1eab3b9ec161c7d2d5f25ebfd6abcfe0033832779c8439d4b64e0d3f2cbf5731a635a9d551347d1520c3df31a4442581337f5271267beed0d0a20201e444f2e6ae5c5a075fec3e0fcae8a87953265037502055a972bfa716206514b4e1a37e80976d4f60ccd4a2745ae98a239967b7fc52c70048133086b3316f4da819e44e0ea68afdb291951f14d5b33c0d0170727f2592319cce3e0069a5cf1eddf898a40188993833306282e7a357efe033b04d55e0d3992262d48a20be64483c333865ad7329c19c62e49f19caaa37c0d0a4c202feded620f8653b2d06c9b816dd80518c9d1dce1cbcc0875f928821471fee26472ad6cc2ae2a4b75f05dfae4a9654f1625301fbb2784d9080e85c7448551cc1ade66fd97329581f9e1b36fe1287cdeee645f87e416901062cea4e3bdb042f5d9c17a0e511b66f378fa3dccf3f809d5dad2164d00ab271cc20d0a692069f06059fa598ea32d104e014219ae8ccc3e14788fb79b35dcfff963df6ed228fbe22f4573b6f042c55497d70b7e90c1bc6d610fabdb83e0e53f1626815884f580dce278024a6ca81d62598e947e6bed51bd41764462a14441046d4fc436cd44f9fc3c0d4cd9af41ae7e7239cd79e139640d0a6b20202a6ff2bbb3241e3ff1199145a803f734acacf1c0cf3394b2a3f7349ff46d37e16248d5048fee5f26a4386e7fba4f35df18a431be05ebcccc89b16c310acde47f9b2541a380b6adcac07f02d539d76bb1fa56cb34482caf857bf97a9c53de2c383b0d0a6520b68f0dfb8f8f5c401b8fcc5c2533cf7f926f63a7785ab6f1e52de7a92667da9e4cb5162b2234469e2cd77427e9421d0b5ce3d90a545765a8662bd1ff043743234ffeb36d50f0e46d9d9095bc69bfb66b3f091c88b443da23a9c6ec36d021c55e2e48e0ccc9f10bea5c0d831b3ca20b7c6051346e7015ed7bbec794854b63b1511b4e7617c734cb9d91854cfd0d0a20204ed12678159bb0e870122a76c4694a76a913a56eb23cb21ad2f6283f52953356903c5ff32430042ffb50ac84674c52937dc7a3aff7a588ac830b9c9432af0d0a7420f3e9ada42cc8665f85fce50b09b94da70b38e887b26026c9dee1615529519bc4379b404bb94e2b10bdd1502a861bca1c39a838ef4674d9ae3f65171ee93b9510baa05546ae773584205f60589a5ca6be5005d61d5cbd2cb4ebefd3e20fdd7d5b3dd0e5a1483a2bec0bcc0f0ba58af57ce12eb8962f093d1316d645e8a37b9963cf1c46331f2a3f9a91e1a3dfbb4d496628e405a767b1e5c1e530eb7eb3fae099b5f375860fcabd00ce4c0cefa36484299a64579b1aec880d89496d0dc5bed8b00352c982a9c75f13f909df2300c9e6c79305ad19a32637d19207fe58530969433948307dbf812a82201112564fd52dffd8ea200d0a6820423ed19773461c4afead5daccb42a2e266538660d147e77f3450d8237eaa708fe49b6d9481ec5dc7121da411f11f4a0685812e84d6a9d7b5b740abcac0bd7953d0789bc2fc21354c369f7f9323882b5688368829894010230644e816e3dc41e98c341da3c2c1cc719b42d4b3f3e9ba8fe16dbf26f6bed22a3ca0aef9d07d93d92067719ad7a58fd63489a1637b5752011f579aaeb74e58dc5f08270e553793d26914f9d96180872677c1e3027a59d60d0a692049aee780f7781691ca0c0751d677f481addb0ab637864b92f9fdb962e7f4f45b6bb0488e8e0a2729d93a40323b8a11d5a58e33a57ea02c69a271d5e4922e000d0a73209ec862189cba31549faf7f8a92c1ce32773aae6cb940f6f7c67c961573a9cd4ff965a2d87f2fb0f4ef8e03c50ab1ebac0ec0cf6d09f57654cc795dfda8afe912bc4b011a4c47598fb7963df1302e75bcad5a4a41e50e6dd0191978af5cd60f1325bc1d4e7a8e6d8416cb0585194509eadfec9096d989ad676157d7d0913d51a063b1b479935ef888fb22036fc3fc7293b3b4bc3320f4a15e8ffc1af9f693d40d0a2e20c549c228021255f3ffa568da1de61d9e9918dd9ffd678de224671ce11ee7f0ccc1edff459ba94e4e32586355fa674fff47d484d8c7e4cec9a197266ececb882272047f38886716abbd413b176d760d0a2020b58940833421df4bbf670f91236063f2580937a825b43c386b50df0fb6a2d2195ba8e2c6c51563303d3c35bf3d687bff1fd6b6ffb9dddf72286ae8a015a434cfc02c1f8686ba53d56fbecf1132923ace050d0a3a29bd6b6e4ef6b489fee76441feb12d389e7cb40c0d257b13f194f7e4fc384351174c378b85a5252147e951ae8411bea60899bab63314777932c83e1270437a0b67373fceecd96a280d1045856715eaadcee254110b3b7aca46c41914f2d21654272d124de275b59729024d47ff8ab89b22fe7852477c2cbe8bac525ad9518eaa0d0a20208dd25ae30a86b787a86dfdcb430078d74ec3267a243791881ecc0b5bead8cae9b4178322240882f56dabebf7c661515dc38229a1381ecf2194884f9127a12d96c29af1f3f94962748b42be9896a62ee3e5ef808a5b66a3fa1f33f2e5b338c2cb8f60184394f6f2efe9ae1f48a639b15cf5034df7b7687f0d0a5420ed5c6e5dded93b7310a645ecf311ab939c3a486d511ece8bfb2be92fab60403d249e62f06fddf17753c454ab14b80ac4761de0bb9cef9f5c3f0d0a68204b53388a72e04c61be8f19db704a23e64df9bdabe4d704cf081c16a9c577675462b736eecb27ad8575a861f64c0d0a6520444386efd170fad91d8d9d8936ed576c7554d5cebbf18191d858e0417a874a99ef45613b1f80326b40b4a6be0d0a2020644d21522c5ad49c6f06d75270f0c599066b4708e324ff499e5ab5d321742aaf33b36685e7dd9735ed1815c54c159db55f34eeed1bab87d4bef941677f439b048f559a997f8941b76d52bc3b2b63d5f1b21f227ac9c264314bd327037d00b8c7338b472b59ffaaa242d8c2d80d0a6d20d531096696d128efc37f518d9e9e6aa4699686751bd26fb3beecd352f49664e77d84cb2b362eccd159bf981b4a8114494f33164c90e94aa50dc7540fdc0a8cbd372be4bcc8054b6568c971bf920acf39dc73e64200365382698454d18ae894c75544855d658779e10d0a6120c86cfaebccd9cc3838d447652063382df27807a6f805a3725a60b84aa121ec23a8d2cf2d8da27975c9a60afbda150864bba9d37804ac8f4338b801ef6c5bac3852f4e84048c6f72564345668501dce6b7dd6ef76f11471e7456b501e8b258b4f72e649b45dd8c2bacd04b1c299c422ccafa0f3c00e470a70c56a978297e49a072ce4b235a9a7d41a64c760c1163af16bfdb2712dffcc255bb9df4123f57ea45f944ca20d0a6920c322cefe8772fefe54881cbf0041b7851c6b93d678c4575e18243381eb714e242e2d272ac7d101a0d53f1ad82d6c00bb8d99d9065c58cc1078a969a50d0a6e20a12d37ce4348fcfd601188d842da25855b2188fe46c86dd4ad962abe6327f3423f2d51febdf7aeb0323df97f42682c0693186aa043ecd18dc1496cc1f0b78bad4a22beead3db4659b34abd7fec095eebb6c96a8e766482a887d7ceca3f67d1f938eb2d8eccbf5dfc5774f792d4d4f8179ce17991303dc511782861056675386e2e948149e98042560120b7eea7185296ccff114364269114430e1548fb97ab5f05c0b903a32bdadf4d9a9a5bd2fbf54df5707d58ee14b7390d0a2020a2b082febb143fc54d0fb300401517b70a81a3c523b20e552b076edccf4d50eb41abd68df4e5d973dec9e5bad5338640e93c73ce0896b72028dc7ff4a0e4bc1f198ffb19d10b3dfe847cdec453bd02882d115a29e657c7b5e0564e0f377f2fb20a8dddc18d360299e440efa4b60145219d2ae07fb8b150be6cd68b00f2f624d69a5be89b9aba6c3b0a3f10080c0d0a6120cb8fbc85c160203f39649d36eb817bd7d53081f3a838e4761bfa94f04f58d1e431f2276e411608db6b59f31d96ecde3e818b489ee1489ff9fd558e124856857a7bc5270b26896b1721749ce1b5a0c922b7ce4413603d1b749173bbdc191411fa4ab542def6644c499bc60d0a64209a301e1b9cdecf4ec29afc1a407d688236ce6b6ecdc311f88e3da601d720174700f66d28646480a6db83d7a9eed22e0dde0e4458a7db1b8467ee46285a4a93cfdc10f21d4dd64afef123e87a11113786de50668bfd979f93b7aae014e3f309eb6489aa0b58d9c291e17af7d6ad72b65b69b6d4bee849fa358fba208407e051f80f24d07d45b7fd41a0b9771da1caa7cc77bffe995a2e2c0dbc1b9e0e0b73a514a84ddb2f6194b77a0e400d0a7620c3ee56f272667f9d49dfa1bdd9020b738f4cb57995b999eef66c5104432a00616d23249bfafa4001e1669fcc25dbf997508a4a701c8c631fb74b20c58e2e91532c628726aa2973f73c8ddf31f01082584f85692ea5212451ab1de77232ee85d2e6d487b2585fa635cd911ae389ea51930aea15e32a54feab22c7e1462dc58f38705ed4a922dc969f463cff60bca6e5139ce54d544e0d0a6120acc62baf053e52ec5df71ea2f3f7dbc443b8e9529243880b4376f51160baaffdcfb33e1e9658a20ad2c5adc447793439020db0ac7f001459c7f65c382191bc16b54d4b3f7a38445e57337111d9fbdd1c9383ac280451b03d52e416b39a5ff91bb66bb4925f7c5bdb7bfa62def65b5f21a3bc34b8ba335e88c50fb6a4afd8bbccd874b961a6d4aec278b3ca7fd4fdfede0f69e4a410f1279ce11c8b6a20247b0d0a6e207eb70bb633a6f1d6d8efb853b7a02b729a9a2e2f5520e953dfb10928614a53063aeba01674d82bda97e8d12e41ec15c4ed2b8ea6892f696e8b9e2d0becc6c9b18d87be6f9134d3ce964b928af7ba8606b83ae3d314ff1d61048dbfeaa3893f86279f272b1c247df2fefaaf286154af8aa1458cb2f2a2456a870d0a74209763b352d43543781c8abc626a642a923e41dca0a3099c7a6bad5042a4f472f28ff1c56e8dcfa149257be840573d62e17b9355785d52d57ed42c92743ebdab64fd37e42b64f10d0a61203b634d9c6bd4ad654dd9a46d90478c1c378eb877c66e82d4751a1d53284a867b7b1f5441f160fdcff3f6735979f26d8529a0fb9ecd6368e4956c082bbd623ece0645dabb6f49fde66dcc9f1432e3c18d569baacc2a429d5109fd77d135de797ca7c805760af594938293ddaf711b991ada1a39adc06c4c62e4b6be39da7c4b1dde1120898af64d7fe2f43f4d42541c76b9b0de9365d0aeb4a2f4d20d0fc41630ec032334e07c0cb51fcb67daadc920bde27f5189b289c730196bdf99c59c9ed4a2d9131bee88e98c0d0a6720362ce1ea9c95ae5ed7b7ee5e9366355aefbf1c9d2d590adf113ed2ade0ac99739da03a21579e4151c55f972e510ca6a283456e8d779b18ae427554aea9f4083aa39bf85d1a356bc5a8a830c4c3ecc7c233f99815d552c3ed6a0d0a652009faec42d61bcc1089187b4f311111cefef0daca7131395e9d79012f3d1dd3cd848e80c81e5c36a4cef5019d9fd6b32a75dda4988fd2e3ff9cefa66a17382f800158472e0c2e182852d0a2fe5869361a574c70f397b10201908090f69581789418a2fe58f9bd3bd82217dfd34f5392b2bb182106efc458c19f878a76c08dd8c5238ba325744e5b40dd1ced6548e4ea36e896bf4c84ff3d9fe6b2e33eed1be4755ef99c02490c76708ce9694a939c5266a0773d6d39c33c8500a1745325299ad27ed8e995dd4a1878398b928c7842e05debf3823906b5c45550f22046bbb5c72181c0a19e82adf12f40326fa60ff9418332f2350d0a73204ad1d75dccca2b189073b340e724a7400431ebfa565493bfa299abd71e1906dff641fc45552f41b89695bdfb2cb8edcffab810c4a065f1d9afd2e13197a959501a9a4be65e0de7d00e300a3b848d359464b852897508beb6c84272b56ba994c4b5fba0eaee1a740316c1cae1b2c7cbc9a1551fbf51a2806789cef7602dc0bd09a03b3cc5c88f019e70e06c677fc1695165737bccf8cb150cd52438b39c21ef790b40aa376c080e0d0a20201f89710ac2330a7155bd332883260401ec8b82679b862c5caf37bf3e7f643c93e3dc7638019d6d712f3dfb4e1a33ab846120a29401ed9cce2f04c7e6b632727b1ff5a63e64a41dc043b8c22c4898f79b10a87a1eff12463ed7ab279374d454a61ef18d2eede31bbf9a6bda0d0a6f20952e6bff47e012a5b57039af3aedbb3423302c1ef445652d6728212138e46338abccd0103fb6f8039609f68e432723fa57c0bd0d0a66207e8cee6b0d534c26329f93b6148eb4ccfef411547ba1f743285c007c998cc7814d7ffbe36cdc59b60d026139c1fb4e28e32fb30d0a20209c8c71041ac5e70c9d376442ca65745dc5dd9b02203db168a3ca53d31b9649104976be6e1e2d8d6a703306413035e857029f9486fc970016f2e1f89de52b737402e354e258cbb6d45c0c6c1952d6b92aedd025e0e4c52fa5f88527bfea82970bb659a03a2d5b0c81d5123d1867a69d77bdbb1fca950676d82ce3755300a10df309407305829ef2d80d9cf602ee7d6f41fdb541b99d42e98489b24d614162bbbd8fffd08b2d18a220fc3d113b9f1f50e25ab782f53c40e58cfc5e59e6bdd66a21e3986e5e5c4f31e43d90c809c8abf8c6b4754bce3d5b1a663f200e328e8c710a599d636599847188b4e47f190ed198b7d00d0a612091e5f33a11a04e689f9d649caa1b9a90da7f557de136a8e61653a0aa104eaf330ac6367a87f99d48d8db517431690d0a202084ffd16c7c24c0fbdda88692a46f93a66e9b9cbab4aeae5c090dd61be08e7b3ba38727e94eae2bd889e2e5c6a8c3b0ed9fcdea8aba91736a452010d5096f30ac4cb9a2998ca85bbbc2bc132f76cafa531429fc8eb7561e63d8380d0a6420c3659b0977fe471d026d28bb331d1bf2247a1e99d9f9d48b00f61e0473c06290d0cc1adfa569ab7dad0730395d07f3a849e185e4fc8b2de97df2ed374b133c947ed6e5bddcb0689f7d17580adec68bc21d57d77d0a449426cdea7e7ac8e90d0a692066e62a5566731d67d8d6bcc43bf81905c7d7e8c97f1b5a196b3e98c712f4b651fa85136f9c1f7a2529806235b89346b00207af3877db29208ddaafd17e9243eed830fa80d45fd8f99063a3799adeeb06001fb6b88e9bac523dcaa8a5d9a26f7aacd46df7130d0a6720a6a45d20e2b21a34b22c17759fe3a1ff1d5928b87333a201fd005e3e43657247064b37a360b2a3a2628bc376e5778b0697f321cd15ad2a85c6a5ef9ea33219e784a64e917b6ec63e1c3a29f4b50ec40e91d5cc3157dbaee9a9309e0526617264f46a911b8eb5c193b44f1ff7d8acbb5a51e86738dbb1f42fde8f2714dbb7ab65d6f1417ebd0d0a6920848ca071dcd66a149fc305f9f1f0c3634a3f3b9b24bb980e85e60683561c5db783c76eea3bf704c4ae71598d76f4b9e40d0a7420413b2daa0a25d83a46bf55e20f64c7157887f02705e1c551f53a3197290fad606b5b0214c3cca613b3df3043f7da2b8abbd5996a6e847c701b86bb1f4a7633f2b958260da722c76425e77b962567cea6bc2c94450fc6a09b1170e4b53cc0249f67431290586ad7e07bb8528c70e25f3134b929016886c9a468ce271be5fb2c6b47070d0a6120af85faef8e71447b6b90a10ccc17cd8962b33c093b0928508c6e6186fea923e78c430d5e00e7d4d7217d01d1fdb651415f573e7bf472249055ac017c4afd86718cece36859f316981dc0222562650a681a8f503bfebe8a162c7fa80d0a6c203a3587ef3312427a1f33244412c74368acb4f00b26ff8e9cdaa0f89658fda195f31f37e3b16a292ff33a46cff8ce9fab623a0932a70c3b94700d0a2020983efc342f3e9ddb7b84c902b62dc3a71d3f0388f4859a03b1537881f36fd02ecc0bdda9f7009c0dd8e7877448c2c23cc07766e57cc0e84786780ac62187088e6185fd938f667d37c067fab76495f85c80aa5ff08e26ddcbc72cdcfd87c163765f589b4bee1a0d0a6420b01f522bbd57144fa04f6bc2b8b6c6a07a3822429525bfa14be94c442f7e6d9c945807a09708e84170b36d8dce7f4652a6cc4e84f452f5610d0a6120c0bd8ea00e1a2cbecf3466d9f5826a35bf0e8d77471bfa7d348e87613e4279e848646dc7593d8b761dc27f854a5244e7ece059f6dec39632dff07aa7df53dc39f0ad61ac31c12d806f9c1a7a5e786909e47b702b89f640cb8447a9139185367fc947743fdd0d0a74209df964bde9e9d401dc6c4b3ea5dee2b99433cfbf55db5c72c4bd30ccb19714dfd27898609c05cfc913c8531a4645b36d470a97e78a7edb17e80e69814db4815d5b8abac67485cd578a1c14c9e21fba771471ec828d16078fc810caa791e82e606f24eb3cebdf2279dfb15b310d0a61200999c496ae6b2beea515a9c27070a80c88c4cb94372225ef73bd969a6b864db7344a4710b8a0a4fce1e7a6f6b942b8298748407507db695e05c7c36673794ce9e8ff89c9d5b16b3930ae3989bc29d597b79eaecfb3f05e883fd00ed3f3ff41006421023d16a263d55a6e4e163b062232ac2b4aee521e96d90f46a5d5f4287775259c6e7484630d0a2020ee75b750481297393144bf444adac55b3513fbc15cb463365774e511d150ae908aeb505e65df7b6c71fff120512e61c15c526ce50a08d63387bd02a794d8b08edf2eda3a30869a2a74e6491b740c44f2df51d8757bdf91e12616b9e2b3e5d40df4d4337c2fa5f92d2f107f36163b52bf3cbca4b5284af1cfb3b1f5d21936c92b7260625c08d631cd8b659a678d327c38b1a1ab2accaa630d0a73204e34c9aed34ee564ebc974430327796ace0632eb4c861815cfeecc69946ffca904af8b761d7da78bdd0653bc3aef44f996518c5838851249d6abfe2a5a946f05a7733f906624be72df50a23da61f13b539d87baf6f9bdfd672c45be6c585d7e5f9c082c7b877ef1abb2be00b55b8c03cb265503d201126f7088b6117da28a301418fbf42fe0a7c8dfe8f7a629382c526c6899e0d3d45e947dc4aaf961539b1be3ce59a6793d3bda358725d527964a1a9a50313a590328ff78ccbc15e1abd63bf1dae75d3892a9bc5072f0bbbffac8621e7ab661e33e8f868e91a782f0cbd350d0a7420f6555fe503464d09267f2db9328d7521e0fca7eb1d32d5cd459c3b609d1aff4574d72a247b2463fc0ecdae1928a0e6bc0c8dffb5e290285942224ed6e348aea98c3d35a15a18310602365ac81315824cafb3c351ae3f0b7030759ff36abd135d3958b1e83928b2176bae93ac396888bd6eb64fb418ca037efc0975f095251aa5aa3ce767495400e5801adea52e0d0a72207a4ea0f8256dd47d3d40ccf6fe1cad20df157ad3f15b15fbc076f3144631cee25c5c1a98f168555bab6a55bab90d8cdeacb9afe724f9bb16c6cd771ffe9893f0ff0324892c45f6360e25cf169523bd393fc9e829eb872d70595619a5cc8cfaa4aacf13bbdd7e086aae2886b8cec116a13e707e0d0a65207b97550659ff4decc16d143a53afbae032c4375d62437045ceaf14ec6f1d0c6dcc7b666e9db69c528a7afa15da8ed657c050ae662c16a09eb9c1845f27f238f79960faaae677b6f9f3e23d20250be482291b9873d49c3cf50aa279ca952fc96882177eb3e5d9f1a994545f90592cca1f589b4080a377db2d0d0a61203a568dc3c64de5d828033e1d39a1cc97b6a07476273afe70e855599115af6ff242f712f9f14256a59d934bf17fbc84b17f0015694e6f5eb9fcf727349a0eaa0a15b94499206e3f2f8fb40f3db3230d6ad1aebd7865671d8ec3a1f0bc1b2f9afea019560b8d03b46d46be344ae52a610d6421edfc0cecfcab9a0d0a6d208978679f49857f4700fb49fbf3b5cc679a54887e5b47a4be889a85e2f367dc8a6ca9ba3f32ac1a9f23ea95799ed3654b978bdbef4660fad214a2d72d7404943ee24f795d6290673aea995ce0e65a9effbacc5b6aa31f3b3bbaadbf3830426f44cd814346e9e24e0fccf47fb506000a919f51a9b0abef9d617a2ef11736b102ee53b2b4d384b74f53d64adb5afbabf8a2ee8993fa4c10e0fa73263c6f31f1f909f6e4e245cfed6a289c010d0a202006a7bd4e663e2245d613628077aa10cec85eb8c16f1b18e6419734f84b3af451b166ad2c254642823b544a6edc144e6c26482b9b7518a8dc0783cc35d2b649fce24254d0a31951f11a0ba5ae310b67265b7468ef163d65ee44b15a4b1e2311a385289401ba4360576109c8bd9e5d63aee055017b9029618efd5b5775c8e4b0de809ac5266fc57dc2decb2d19e936178239f5665a9e0d0a6120077510931dcd7d855bb461c608ddb07fb111abb97496e47b192fa02cc24d679f9896222d96d188ad204afc5a2e701cdf6fdd59e38a6d0921d09c7cffd210464603bcf025a918b1e75998211aff991e0faa3b1d0209de83e505a5f18fd27838fca08eaa57451d4d66edb2d140b568bcf7965cea8e762d759f4c95db1a6be6dccab9bb3cb67387a49adeb719d52c334690315848f1a808f1dd0d0a7220567d92751dd5a270f46d92be6616d649a1ce1fdd36226c5f810d4dc72f6ee0c5ad1e8b2230173ff8a534ab87303e36db11ad54b90ae9036e85888567aead28f17aca48ff09bb4327c596f9ce8b0027184aae005d8b847494c883905600054573e31e1d09348fe37a5482617dc252bb0a936a7d7785ac76bca94294948ef30b0d5ef70d0a6520ce7a6132c19e77238d007bcc30737306f57f58a5542f8554c82dba91d8f1622cabb50bd9e6fd9722e7cd4cd690ccc343ea8eb6fb4d05246f87e457f8f635220acdf8bd373fbc4fd72bf9bc607557ac0a0a4f5858b6f36990bd113d66178af836aca98c4b48f83d89b124cf7602a7c795f43b162ebf9908e4d708505a26cb177e204a07ff940fc8a0c850d27692708145295983a7c931d07383cd079132755019d735890e6b4bc7493b847df2615f4076b53cbc82db00febb0d0a2020c4118525613e87b5bf89fdf7b89aa3c6c57db937cbc65528afa1d0fe0e7b39f9b0dbf8243dfcc8df6c76ea192d5e4f74df147f9796724f13a5fba24641877d3848f4864eaa04689b230639aecc7f667b801514a0e1d28cca2481a64df89c584c9225e52e971f6a0d0a63203f8ae53b47209a24359517bfb2dd4034e86ad73dacd1e0806a252169a62fb9914345a38cdf6e5227f755fa2e415df05e62ecd76a17f7666645019a36011498f3a479bdbd1104e7264d7ed1d83007a6c34621dc853c48491c1fa25c63b9279c401a67a51878ffbb7a232ea5940d0a6c20c0054b7a036bd92aea66c07fdd1e18d6a7c4895522d179ec444ea2cfb647f019963e2904d243c72a159bd6800b81a1f79a984d30ae4066a8ad9df1acecad0240e57e3c9ae04254e86e41f28687c62668cac4d27f98e120ddabed76502f0ba22b2ab9f9e721eb1f6b420c7856d5400d0a6120e4832be3558b5ec9a426eb798e50b50cf3c905c5c3461584796b17bf69087f09f85f77f354ad25e5424673f2662f117061f179259eabd1f6c4678cf42e22adb31e17e65009b9cc5e159b1aa9ca8fe16fc2c52b57a2d170bd2ee91ccb99dda9d78b48b623b611a7c70f7eb9f83c28ca8d3a39cd78699bc65cf9518f6959d522d2c5e46efc479350b20d0a7220ba97ccd6b5c159b8a44635855c860c0c4a718584fc60a1a50391862d9be3645dfee5fa9d71c6cf6646299d3888b88bf4723c5d98a1a3adbae1ea8b675e73b48540bc72762a7511393eb8e3231dd1e10d0a692062fa25468d4c7d0296517b9cdb5691e31857af79fac43522101e210915e1b84f09a9ecc05e355c6c2da603e4d172a7512fa5c6d438987185300cc349c6819f69fa2976352dfe7b431867807d63873189ad0d0a742029a137ea0756b4d411c2e7b048cc0465a185915e735592075697bdb048fc9f97a33a17d824b8b7521effcb86504237363429682305058be85166b8a3cc6e6a7d34b534da92ddc5df4a76cb5f799ce418d7920dabd20d0a79208510cdf6fc33c67d4114dd161e64b5f1c85f02b55e1a5cc8bef6d0bf705f98fec4be34ce38f25c27d61e1403eb59acf65e6e3b9ac0d508c4fc7dc9c2bc3a192c12c9b967b888722c2bbfc621ec88aedf0e4151f6ea6700974031e3d0475035b442ecba202c498434b9977f8fffa80d0a2c200ce15b24ba56eea5884e1ded5d64b9dafe0f978e93ed8c37901c21af4f63697f19493dae37a4289b08f9beaf56d45fbc40559c9de7b02828c7456ff219e9a0b90822e32004447f90819ee810dfa999d08c1f0ee395a3de3b5a7341ec577f18f7e3263a51b774d4c10677e964951195d152aa0330d50e2eaeb4dbd48e6244640ff057ca19235d46495d182e0c12e8430d0a202005f4c66bc6c871a67ca42a5682a793077d67676319d3941e4495fe5c5553f78f285fe0e1384ac9220f77b772adade6a618d095e86fc1e2f7511ccfe51acc4c8f6fed2703c2827122b412e435a3eba575db63190f4a015677e33bd815f102712ccdc9ef199496187b6198032be829ebd52d6c48163b87bbe7247251138e77ace60c1f9668ba39116b24d1c2eb2e18b82528ff712b6f76b59de1a90d0a722060fbd6549fba215c5519cc58a494f0b51c1ce1e5ca2474eab509365e490c03794103c496446f524fa7ff55b89a0113de0d673ce2f73846e606713819ac52aec59bc7910f88eb7e4a5a51de35187176f64a1d266de5f336c2694c3d975bd4bebda548fb3460ffadd3aa4c2e8df6bf440731e6bafac8dc5c76bf64d9e91e69e1efd57e0712a4d5246b28a09d9175f7268bcb751835e7ac76351d3bd5de472490620d0a6520d368bf687d6942fe025ab4258b403dee8b4f458056a6650d93c508383629d65b5103675130b50c6da685088990a8ba89b877808aac4a78225cd9300b4f56813925a7fd3454c40b1e69f7233e9ff00ca3ab2a9a5dfcc78d191cbc534f8442974a22be04d00a43eb6749edcb342ffd24a1dc9dc2f770f066c73e2b3a5d233969f2928e401064f1c9e8a420efd1a628d4a56008b29b53987e2bccfd7253b5d4ac4ebe46ba45090d0a6120f5c3068758c2f30599e9947c5ebbf02e8f7f5321d8acfeb2ba0f6e7644466ce85a624e17edabda187022ae3dcee937b95a19869d0f575735fc982a445da0cb18eb63965bb15e9bc00df46d927d70ce1fbe26e2fbfed19cb352a35d480ec73a87f6dc05c33f5c5c75d07d27227cd5c32ca267de3951a318e8fd4e40d1fd35c27d272403d96445b0dcc4f8bb057286467ebcbab76ad52ce372cac94bc1e2484ec0ee5aac00aa0c0d0a64207ab408a47ac6a643c2153baa19af7a166c4174d24cbfa4d572cd7d086828de49b655d00710595bf06d0ce848ef4c1ed7b9603245e0e21210bc43870ce792842b5b97ae0f426df9e57221ce68f174b2c9d857fb119288a51a4328fb9a8e0d92bb862e42348db78a02d5c49ce65bed181ac578551e67eca5ba3f2d94858378a53a31375fdbbfad5d4a4bda0f08a398b779ca4449cc7d47c892621035307705ae13ed326a83102958fae85af00d83d6fa4040ed7d10017bd88705e11434318b31b7c379615acb0c6423a206f5d1851528057eb91a52fc3ff10d0a61203ab9bde3659650bb7d4f2392c8a9b8be1bee7543f9d176b9082c3311e0a1d9845b7a0b3ebb40928f83a916fff58ae81fdd4dc27afc9960251ab8485ed97937f214a4e60caaf2639fa71139b1d7558a1411903ffca31ef1df61d8d81e18d2b720d200db314e9d74ed79044ac463ff4eeb27daa31bb0b7e22a0ec0e9225d8f0980009df47627105d51208c6edfa718c894d7ea92ef6e06fbad37985952038e240f3943f09e9eacab84797f0468215640f5a9f3f4b0092b374f2cdc60200fff98c513c9f61c0d0a62203e2292df4d03f1b4b7c7dc7da08cc4f73ddf99002cfc72b9ddf545b2e256dbda08167290732305d4bd42eba3d366c182e4b1714bc6ef1b9b687c5bf36090cbde3e1867d901e4e483e34005732410bc882aa45d55c87c85d243b72b0d0a69204f7a0facb3c7fd8667203faba600a0754aa13f01c2fdef444ca7d6eb456b62ea36dd8fdf9eb85cd0fea7f92931f901245b2256b71f06403b231f3a3693a6acf8d5b9bf3e1151326337aae294a0b823910aa2935cf75954eac6c67b8a1be39845d753ba61fcaba66b2cbc6155c85d867e353c62653995fe4faae5a8559b783199b7805287fc9ae1e12d0fa61a3e3bdf19e9eb6767f3324f922c6e62c0d3ca99f2867331b1fffa4aa383da4510eb78fa82213b70b07a0d0a6c20c22d550dddb53a9de08f3a4c8c5caa7e85c00dac045715c80f5331125ffc4ea6582bc008cd5a7d94efa94d0cf158d059b2109f7cb21e2df6ff42c03af7b47113017965423983a5c532637f124ae9cc4001d357a62991de2876567569aa7e058696725ce1cf977579f10c7ce3561bb34f9c93780d0a69204984c3fc7922aaa9b443000c5c898f08bd2ca34a8ac5a78a1ca9de20396ba00ae6e3161739c32cef663d9d55edb0fa82e8cf06c2c6dd7ad981e2cdbb0bb2759511a9e465fee4b0c9c6a6e39d30ec0d373f67476dea79a41a3ed7b658a98588adf06c0ff6729a0cd3d06e07e1baa5fc1a26b424ff722bb5ce303b2d41288a37a1bb1390bbc0b70d0a7420633b1a45cf71df1da79d2b7347a6d74f2203f688a9769bcb6debee88a4dd333b51550ea57afd98ea3b2ccd117d86b41b53a45574d0e98588b1a3b2d3dd570259851896eeede3e61eb4527577d36d37eea91ffdfe9513c2cea1594c3cc16e33df8dcc3e6d91ed7eff4ecc14cd41919926bff2b90d0a79208f71dfb91623d5eaa9a453a05e7f48bee3dd09267b37358b6cf1df16c9be20bcb38954b541fc9f6488d3049046027013fc11c129c8fa1fc6c942bb1568113f5285ac0c00c4ee9ec95e41e5e3e55a23c2e65abaaa0d71c71eef6e3fbf00299d86abd587d415ff2d8d66b96b99d68438fce8345a9bb792105fb5243ee10bb0900c95b352f028c4b6100b35e1b52b4dfd475a140d55d1860d0a2020d900cdd1b3a97e3b1d0f7b1f714e43649f5075c5634a8fcd54c0b846ee285a224cfac5e674a697be7c575c7c66fc611384d447f86813bd602c4abca2351e8f1413eb4f10273101c1f398eef224a9dd0dd5cf49273bb4811f17f1dc9381cce27012c6d4590d0a6120823b838f94a4b71bab513e9ae4b36f9724d0c9694db74ca546671c14deed786ff63c502aff3396b8ad576bcd76d84aeb26f68c72e8635b4ba6ea9ac6a8cdb8b4769beddeb10862b316359aa93c95a08dc7105eb74b7ef02c7bde86a1b8c8b3a41738676779978ee1f0abbcb9daf0f7022c0d0a6e2012c6853733da2cddb7c7a58f79c77a9bb2358fbb170ec124834f0c4bd55eaaf0cc1109bd0aae1bfd0d85524742a818d0b1baee8e49de15b26d0233ce050221f9e07e2f75b676a67ceca104429ddc76dbef9053e4c9f935fe865a49eb232c98568e74ab2eae757fd122ab58629289b9b2387bad7302c5b0604b27e5e4c411f0c884196d9f419998652259ea2f0bd6ef1f822efa660d0a64205e35abb814d0a87de631fcf0770dc873b1ac7533be34b4743e8b3f7e890299299c057ea5fa7bc38ff767fe9c46ebe5ab62bb29463208e239797e3353bf559b81b551d8890ba97eba5318321f288f4b3d047a49a391407929faf7e94d4d91239de55bbbdb00a140d01fc9e60f18a07b42331f759e1b10355bcfef57c9e83b397d5205a3e4b80860cc4ab712bff37a90c5234ecc941bc46c58f86c7694f1835daeee77b207b47d96b658c1d1801b3ab6fb1a9e1c54a10d0a2020894e5b722dc3d1f3a0bd306de6afd137dbb463990e773a6c9f6cc087af6845ca68e5e815006309c3f2360831c3175148b1ef65e4cec0354df0037146a8ca49201fdadbab4be559e3aa2e6ca07dc97ba73e31753f2b7325df8dff461a8350bc80f277d75f37c2c2eb80ed7f85c13e33f057200635c397668b579171415d1dd58b4561b2df2c61fab3172f61ef832ac2405f57517e1922dee8ba0f70f77450b6c1bb863f6a62ec05dc4e9aa0669e0b8d6c53a31fa2c55b223ca2d7ac0d0a65202d52efe9c927413205fe447b055d8d3f5ab36fe0bdfd85bd2a418f11ceb5b0f9180e08db00e4852ae063e5b37d30eb5ebd969709ef9d71f5f6878d56f38072e865310fbe7db01df412f700625da7fb7442055098252a2d2f8ff9d3fb984f4ebc1c1480de5a39b5a807c5392362537b724935ad92b77b841ee3cc6f102299ecdf32fde87651972444d908f8483ea071d99f865c1e47e5861e53577d32ace31ae093ea8360ce5debbe53df1ddabb460c08fbf36052523978c47bf80d0a612027c752b38854e93e460c3f8966ba3662ee1874338638f12dddae70ea9cc5be2f80c90ee4abc2286e64e1cc8789ed7ba29129b20fabbd3f6a3e1cdad4cabf09206605b3969ed8f574565e9557bdef47556cfc5d34e36e097268699d0fa5004ad84de530bd99b8acbf046de63636772944d285921aeb3d7c8b0bea2505981f453da101d2e6fdfe2a527e5fc28ab87fb52347982863086f4cf4a8b2262ff5b96ceab6fbcde257abd6c2e7eaf76b0f2b40cae11628ae72aff2ed172e727897bedf5c51fa8bc6219571fe01523e5ec882a62e1e6a15a7d0e87e2c1a02297ba1a06356e8476d1af04eea0d884877d00d0a732011d45f56e22fbe0795930925c5e643a72cf701d4b348779f3a7b03c5e6984631f7afc76bc11b599cb1f698e8abc69c8081c3fdb8c26827ab698b15ed4daace45b8930a83e86cafa4be2a974f92e5ffd684b38e11fca2d6ee43ec5d4204d1504b390c3be4f95e9f4edb754ae649ef7b06dc65f3210c8d621200498c905760a75c09445a6ee361cbed1d6d5e90a3fd497d4da9e024993e01f88cd9359488007779f8470ca381d6ce49128256ce88ad27ad949a7ff0e25b6839e09ee7e803dd2648912c002600a08af49aed472c5b31bac47a6f9f7bb80d0a65206af63cd5e96f774041e85a40d85f085ff647639ec907e6facc4998b3201591cbacc1c3527d05b8d0233f4b7dba2c542d66ad9c401f845f587a553938116165642c572b032a2111e809d9138816fed5eb722dcd02c730685516d8067b91403af5a776e0a056219595750e7b915f6f11c5d1eb1bb6a8f89726ae0efc82521736d53cf9c2587961844faa7a10acb00267ffe95845871c1e2130dbb64b74d0a2ef55b95b61f99137d4d2c1b78f18cccd8d5f490090749f780d672b9103acfc92188c06d79997fdd023924a0df69cbf5b647ee336461a3f0b28f471170d0a2020e722cffe1ea849b5aaa80ba7f1f26ad7bb0ded862ad99c4c15b1478c91f76f83f82154175acd033999e2b64ce5f805f301118abfb76f13ee2fdadf9becd2685da928732ffc094209c5e096504c5fcce0d8485735b47d548544178efae1aaf9a56e53003170c9eabc906a619c6467fda8c811b161aaecf2dc98f1255599c7104692e401b6eece678e552e228e781f9670e374a0de8fc8f15e354bc5bbcf9bfbdbcda316d1c84844a4b67a4424bd3d731938af334ea097c067106a9eb210008cb6afd258eee097084e4da11d4b57dc32854871210d0a6f20b16c8ee7abec8854d61cba7ee4bb60a69ba1e2a2c5adc3313c6e9fbbc9ba440ff315a4b9c07936790a975d57e90440374ddabfd14467395b8969dd68dd7eaf341c9510735b757ca7ffa5e3228ff0ac42a8a1af8fdd645efcd07a463c3eb681e7779e970b80092343d15aa93d5ac35d94bfbf597aeae2fe5da2f4517152fde8d4090baa3cfa6fd9f593ae112166f0dc384eb0fd13d0267750648799555f0804d555385f3de31e2edc39ff0d0a66206704b4ba924132a3e0c7ade69964c58d1b0e559767efc0e3ac73a47100095a11ee0091a0a88885293ea76be5b8427613205568f18c039e8be1d67b545c1ad31275ad780a52ee5be8afde7823e2636be5fb73098614716d98a8515dbe758cd1f67edd30d33264fb8c216957837b34f7fa818d603d5b4bc5f73076db3b1b1a48c6b37f9cce8953ae7f67f613380d0a2020f03904b8054c357ae60ec837e4eb1a9d152a0c7597e8bb99e3df4f59efa3c486b8e551e403fb267b967573a3377bcfe5c6005f6f865673889d8d8c7f6a0376f8afbcf39e78227261c116a832b5fe52d001612a36107162f81147b8a172ef2599a9376d475a98eeca6d48bc49a30d83ea935c7cae8b875186a3d12b8be6688090d061d4f6a1e5b14fe71891d973e898030d0a752099c07a05826c9eaa0f00e94268b8b4d76f2746725bb319c0041874a704dbd08cff37eced6f2d1a2c397ca36d49697b210b63a969405e88fef16c58fd6832a89255291de37aa4cc72c2a73d6157b86a5b779112ddc39382edd9333ba36d0ee96c7a859594c704ec5c290c6dd4fb86e6db7f4bff57660554e7138b7d6188bb4b77996f9e8225e02cb5fe6d109b6370fed27e3d0d0a6e20469c411026fe9816cf9ed22fb7b20b31ec11b964a508fbf099296771952baffdf597d90438e4e53714926d971aca68ca83a459eaabae572a5f7dcd37a452ef4c171ae492293454a97d21f5378a5903c086c4b692749214f25857d6849544ef12b10230b087b395348f615a044c165df80649f1ea46de553b82389ad307df29edc8d94a94a648964461edc693f86d47ffa9a81b3cbdf7e6e2e96136c1f6d5a231be03844d624d59e33b37fdf80d0a6420509801d74c88442dea5290ccaecfb341de0a0f33bedffabf2c91113cf8570db02720603423890f7b834e2dd0c8dc6f90da816eaceb1c7dd684214fe6a3bf3af22ae70539f4fb3b2f41911030371ffa0d0a652026fcc39b3a037ee05b72d5104e22081aa303754ef3afc157dd48dd9e18c1c889c3556033e3ea385b05fa28c49c3b0783b8af685b02063ce4b145d124659b8ec52f07159e302135e7f5cd237e5b19f525180d0a722057b98f5841dd11e9a7ee56cff9293bb382d082b78918c59a3934e78889d7ed3f8828930bf6e9deee084eba8caa9bf589a5acab305d9eb07cc8c3e765570ac78fa3a5098e484f9610083b1ce23ecbb01f629c29348a0d0a73201162c1601cde400947fd52913ea8401f06c03402593dd35b01652fafa547836dde6a94bff5166d07e06e4ebc760648660687a38118d540e7cc7464f221fa9f8000bf593a585c2dc3e07f084c4facca98d0701c227b67ee0ed302569c493b5660c421ae17062f81c38b50ddf90d0a7420c4d02934e558b3e19e1c7cd1ab61578e494e0f0bd3448a4a3c9de3465eb5b4ce71b9555443918320446263890d26b7c494b21447c013edaccf1d7ddbc1a25f38f21398bb36547c1c976a472c3b733014cff09b176fb8bbd1360f2f57b1da5509b09689b3b6845b65843516e418873c9fa1271a7c622d6f9d3b3d7b49f2ca3cb466fe76da3bed0b7597fdfebefc4b5c0cef015081a4d1ae3518348210060d0a6120fef0e6eaa94a61588e8403d09b4f233e1aa1e5ec82ab24c3594524e0ea21e473896a2414a8df276d712a45525f263aeff0c0a85dc01ad631dd00093151ea9f89be5045cd1b1a1b96ba2b38b1d7cc89972f9dcf570ca700d97e3828ba5f33c922f130b9382fedea2c54e0652c0a51da7e3dd6ed6e42a1150f86b18e62eff03d715b86e5052afcdf3d4dd294d99eee841b90a26d9268b73232fe8bf556071f2a0f7f88fe0a13d948adf1dbdb9d6910d43fa9739e751050953fac0d0a6e20318b7ed1cd842378e41e5ef5c0ac515c7366345e7c430458857eec676e55550cf4d7450a296928b98fa03fa75281e18f08c3b4c63620b64e431f53a5712f3c9cf7b864e2ce9aef1413b72f1f28391b90308a7e06503fea894763abf65ce0e36bdfd0a71b039684506f7c22c31f8f5b58f7e9e2bc6e9d1546480d0a6420e1f39b229f140387977acf2defad5d687e5199a25fc7e3e54dd2023036df7e68746bf1bf923d6e44d9bc581ae99bb28d0b3ad0fbdf0fd54914a6826fa12d07ff49fc539d11e90cab9fb2812b09ba3626a0a5a8d2cb02482a747e14587e6ec6f66a854ebcf754112d5d66772651786eec2fb87102fbdfe3dbc672263c4c2d0d0a69203376b674f634c799ec83ee3b1fd5a73284d66fec50447fba32c8b70ff2d136a3205c83dc2fda0e37a0e9f97713630d94d569e5400031629514cad66da8ad2cff1a07b0a7c73365a686e8771477275096707b3af22e614a4d7720237350e28d674410c753f211abad545e8a1a276b8ddd2966f46e5a0d01d80d267cbf2f6c660d0a6e2069effc528ae49e4112ce0881ae09339024667d4431ddfa0a968bef88505de574d01ebe2870e2bd68c368e29285f41a6834cff7a0b5d794f447d6ab005211a759bc98af052578cd944a3f10b62582d4a9c3a0820750eb4b9fb05562054a5cc23344dbbaf8bca6c7ec5f0962682e0873755b1962eeeed4b1204c64cfa755f7901042429e88c1c2b610f47090cf07bc86d55841c41544a1c8dda414f42db0736e9dbc019dd46e18126d0bb79a88c67e58ab0d0a6720a4a7b983c1d3fe4808911c0130c210a3ba0019c4ac9a0470afd48d688eebfab00647a1c865572e54ce89b2b9905456d4baa83eae45be83709d0473ea5b3e80f89f4d0ccf9d929c31b5ce3531d3bff2e540eb0967e974874c0f3dbd144fa55233337a7740b57f2044886c947bde4330c446a12f5a81a06c8fb26fd789f359b7ddc3716c2199e7d45e75332f1c89e518bf71e339219351ef2a4a0d0a2e20e4ef514ef69eb2cc196ebf8611334ec1aff587371a8e91e21d640cfec661c27ba31e0db979109ce958e9187bc31a9a3f51d176d56b6c5b10f1691f2bb6b4a8c41a55e1d9b3c1712c83131d3ef6cfb1cf5ee61eaefd203d0988d5d88fa410c61ce48f3d05a60065915f089f0db66e6cad0d0a20203e7cc17ff531668a03e8ba840e5440a992bce538f94ddbb81e8c4966383468329c0fc689e65e46d4b18488be8b00b7f14d29ef53761a516dd741157a80b9609dfd78c3f0b219d22bfe1cdc617e2dd194e5807eef68cd9caf6ac7c059bb6c5f26b7cd81614d5be7f82030c8450489ed9eef4ad5e335466e4e76315e40a6cbafaa7e9dfcd7e0b87394a3817ba3fca9fc4a09f2b84b280bc184fb96e78357027a24d36ba2e11f0d0a4c20b93445f22110cda9200b54daaf1f0bfad67b3ec2470b8f205213fc864fa82e12b14992b64dd8232e9ea3953c410bbd9642162df9938d644b25111a8368e8cb757ce26b4ba700e51e3d1afae490a7f7e6e4d9af9b282a834455ca2cc87b6c577c0cf72846b222f561982919c0276a2066cf13184024e40cb5965b6678f2e1328f1e067ec47fb00d0a6920554ca17873089acb6d298dcc0a99504e527fa35710343ae378a332c28542f316b9076aaee0ff9f5b61683d31022740e4e47e5c200ac2d32376dd043d6f47d8e0b583e9947ae06da7e337a456273e0acdf59d23263d7974411008162e49aa62bc06abdbf848ea47b534715758c042c18709f49c701ce7c48b3a32361696fedc4749dc0d0a6b20f7916ea5374052277b8473d149459fd49b42ce04d0e3c84db44eb15db4ca420381279f3326db892f24608929619f8bc76007a77b1cf9b6567eee5f1d76d8abe84ea5de64654a5f409d36f4fc9f24fc9c846928250ec917b930e47aa073b717bba66521c58e75a8ffff43c31dcab3080d0a65207eede4f65df954a2d57ebb2ffe290ec1d32b9c7e71004349161cd7c2e227265597fdf6ca0eae35058cc2d8e964bb81a750339aa600574095b4dbf0091a6e57146069c76f2df30178fd81f54bef9b2a1b11d912f9dc1f0638e55f68388ebf29d4a017bfd265106eaea8b3e68fa023338604bd9d7b3a776981dbbc83d699c8c8bcad7dfc6df86a7ac247484d6288e9a8e376428063b3f51b92aa19e841fba12859863e9fe6b5410d0a2020257c4b62f1e51555ffb134087a11acd287a4b8d033590240faf1cf857a79d5da73115118621869bcaf30953e02044097344db0f749b7cd3df6a5f65f2db35ffffe198ced24412a5e61ec3b3b30bbcca94d45b371f1a8bf5961db810ced1a078e5c8ec90d0a74206903e7d157671c18a0aeded00e387b64e629856732d487903ea7e5ee8e15045d4201b2907efc298e952983e27ccda2824e6f74a6e84eeda9cd1aa39e39eb9b4470ee92e184b7d1d8330461e4af0f233c4dd5b20ffc3364464db8625fd5904211c4b677f79a5c29f6d785ef0ab3df70069a791a4e1c3902b71d2214a33eabb1e90ca9125a3b0d0a6820f88f524fd0323808d6855c4c2f71c5db2f2af7fb4c8d3d33c09d3fc734963051213604dfee03b313e5208fdb740d186c193c6967c8a88aecb8a2822dc60c1b008d87f1542f0854edc33c47861442d79f8d556b903a1e689e536fbf2142f24407ba4222d8d7a9868412a9a9aa74fa0aed6b1ac8167eb08347cdc00389ccb29c6debce71f80d0a69208c23c1f0b8d92eb72b7c25b7239f24e6d4d467b26758180d0a7320690c5772a50f6dca26bfab7d1c168953fa9d5dae1cdbf6c89cc93f45a2faf6078b5348ef8081943cf005b8f6a5f5860750baa81a45f2befdc40e8dd064b3b029c8cd823fb2e53a18c0251f65bc26b7064eaa0d0a2e20489119e7391040a09191d70ff16dd52961a73fbb74913b1fbf29fc344ed575ae8994f070f14485c1da28371a823050ada4cc03a318f28f1f9ca98d467840bf71dd9b1746489442aa05de87b1780971c74b0f35e7bfe6f1ccdf29c1378ee6b7462ddaf5e2610d0a202050a69b7d9ce2d67914c85e92ecc72c1e1097235cee395b02257f175259ac93730ea2becd4f1895282fc14aa0f98806c2155624633364dae4277305ce483104d0e76ed59f3e0d0a3a290e917bf68aade88056316e361684e59ad4925b7e3cd675aa61836027e1c056f555a117d2bd4fd45cf507760abd6363f94149c566eb86b180e3498ae8e4ed0d0a2020b74016ba601b19300f6f6dd300f0b4d7119db0fe263ad3ee9f7dc4175b36a843d6b983cbfb5c381d781ea61d27102576ed07330a1cc9923f93bebf0d0a54208ae7ab43255173c03ad0bbd41a8fa6348d1ddeb9114a8463871308448fd0384bbac154aec1e4a4efe433c4ee8a4a0d0a6820df01f7578cb080f588cf6b3141867094c9765f3b1245bbebfe185581c80dfb7ab002ca47cef7e9ea5c5a1b9a65db4defcce1c9a6bbb41ed1b78bc3c6cf84fb1b38aff6712201ee69b58280337da9d2ede8868bc371359ebe10aaa681d460f375d08295a3038a28b4e6846f5c9de34aaf9aa8e4a75cb78c19a7db607bd97b96c8a79cfe10ef942743e068118f330d0a65208c63706d10716f3a638556dca971e905fafe65fb046c8da4bd5ab88517da789501f4a9f23e655154a053df358068de90deb919c0a74a5cfc74f632e6ff1f0772ee570a76d2431b8c0735431462de5bedcaed963e97cb7cbad2324a52408d91cccf8a6730ad281b3d1940ff933d93efe37dcbe1cfa00218c86ec92fa90d0a2020e6b2d2c1e783954de27288e778e76b835ce72d922bb5143c860f7c964bdcc2ad1cce4c8d65d9a6c9815ee38c6058b03bef18b8b3dd88e268700d0a6d205c52a0dc69c8cb3b736f0ca20f3ae6b78049c47268d3a777266b2f0b21480f59fcb5d9870be4e7d2e07b4c0d60d9970f79d81b03444fbd2477e60d71e86ed656749e89239710c610d73673710d0a6120d2bdcad090f6f9a0b4e0b030d233e0287a1d8593d75dc9f0b986fbdead4568b524815cb03074f76b4881badcd4976f4e420ad93bd350589d6003aa02e9d6e54cfc73018df041280d0a6920f24b22af03b00b2a61d577e3b9688cdecea331fcb5409a8edda7952899692a88c88e15521ff4ef30c25363efd03618ed432c326477e81424db17ee63175b9d3fa2d3a7c70d0a6e20632fa8c0376c0e15e278e8ab2dfa992c6946826c534e7897175529d8e8677cf44d46cb9f725ad428f40f2842059310f155e5124e1ae7f1f803b04b01033b0cf8d3b071b616bda9fb3a3896d78d239361c8efc436173d5d0d0a202063a50c95d4f103448a782e167218c45a68ae44ab75c3c19367ab89df6c6159f20ab9562ef87fc35739bacd07b44d6edc951afd019f82d1bee874f4eef7f33eaf8055affa89948e74b514591ce348c0304f8738ec4a0538a65c2cc18bc6ec102e3ed360ff5857b625481947d4857060e12a97e214273df03f7de2d1e9b79231afbe1c5a8cc90934cadefe9b600fb36febd71f107b9275b22c130af4723a92a00c2a67b2583d1b4d5c03a6721bab338631cc34c7465015af934c57da63c10000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark
diff --git a/share/examples/BSD_daemon/README b/share/examples/BSD_daemon/README
new file mode 100644
index 000000000000..cbe8c96bf7fc
--- /dev/null
+++ b/share/examples/BSD_daemon/README
@@ -0,0 +1,83 @@
+# ----------------------------------------------------------------------------
+# "THE BEER-WARE LICENSE" (Revision 42):
+# <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+# can do whatever you want with this stuff. If we meet some day, and you think
+# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+# ----------------------------------------------------------------------------
+#
+#
+
+This directory contains various stuff relating to the FreeBSD daemon
+logo "beastie" and graphic profile.
+
+Kirk Mckusick <mckusick@FreeBSD.org> holds the copyright to the
+BSD Daemon and you may need to get his explicit permission before
+you use it. Please see his web-page on the subject:
+ http://www.mckusick.com/beastie/mainpage/copyright.html
+
+beastie.fig
+ An Xfig(1) drawing of the 4.3 daemon.
+
+ This rendering of "beastie" was produced by Poul-Henning
+ Kamp <phk@FreeBSD.org> and is released under the "beerware"
+ license. In addition to beer Poul-Henning collects FreeBSD
+ merchandise ("nudge nudge, wink wink, he said knowingly.")
+
+ In difference from the rasterized renderings of beastie,
+ this vector-based beastie can be rendered in any size and
+ still look great.
+
+beastie.eps
+ Created from the beastie.fig with
+ fig2dev -L eps beastie.fig beastie.eps
+ patch < eps.patch
+ Before committing this, clean out the comment brought
+ over from the .fig file to avoid Dollar-FreeBSD-Dollar junk
+
+beastie.svg
+ Created from beastie.eps using an unholy mix of python code
+ and manual editing.
+
+beastie2.eps
+ Written by Rahul Siddharthan beaste2.eps is a
+ smaller, simpler version of the beastie eps graphic.
+
+eps.patch
+ Add some comments about tweakables in the .eps file and set
+ the linecaps to round to improve visual appearance.
+
+FreeBSD.pfa
+ This is the font used for the "FreeBSD" text on the CDrom
+ products from BSDi / (Walnut Creek). It was originally
+ found on the on the WC/BSDi CDROM "Font Garden" under the
+ name "NRBWelshGillianBold", but the designer of the font,
+
+ Neil Beshoori
+ NRB Systems
+ + 44 1273 581366
+ besh@cix.compulink.co.uk
+
+ has donated a FreeBSD version of the font to us and allowed
+ us to include it in FreeBSD with no strings attached.
+
+poster.sh
+ An example of how to use the stuff above. Outputs a simple
+ FreeBSD poster suitable for A4 paper.
+
+ If you want it in A3 format instead insert the line
+ 1.41 dup scale
+ above the "/mm" definition. You can scale it to any
+ other size in similar ways.
+
+
+If you want a GIF with transparent background:
+
+ fig2dev -L gif -g '#f0f0f0' -t '#f0f0f0' beastie.fig beastie.gif
+
+If you want a PNG file:
+
+ fig2dev -L png beastie.fig beastie.png
+
+enjoy
+
+/Poul-Henning
diff --git a/share/examples/BSD_daemon/beastie.eps b/share/examples/BSD_daemon/beastie.eps
new file mode 100644
index 000000000000..587fe508c36b
--- /dev/null
+++ b/share/examples/BSD_daemon/beastie.eps
@@ -0,0 +1,1507 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Title: beastie.eps
+%%Creator: fig2dev Version 3.2.3 Patchlevel
+%%CreationDate: Sat Mar 3 15:57:53 2001
+%%For: $FreeBSD$
+%%BoundingBox: 0 0 384 417
+%%Magnification: 1.0000
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+
+% This controls the linethickness. I think large posters look better if
+% you use a value of 2. Small daemons looks better with a value of 1.
+/linethickness 1 def
+
+% If you want to fiddle the colors:
+% col0 below is black (the lines)
+% col3 below is cyan (the shoelaces)
+% col7 below is white (eyes, shoes)
+% col13 below is green (the shooes)
+% col20 below is red (the daemon)
+% col31 below is gold (the pitchfork)
+
+% This sets round ends on the lines, this looks better than sharp edges
+% but I have not found a way to convince xfig to do this.
+1 setlinecap
+
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+save
+newpath 0 417 moveto 0 0 lineto 384 0 lineto 384 417 lineto closepath clip newpath
+-51.0 455.0 translate
+1 -1 scale
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {linethickness mul setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+ /DrawEllipse {
+ /endangle exch def
+ /startangle exch def
+ /yrad exch def
+ /xrad exch def
+ /y exch def
+ /x exch def
+ /savematrix mtrx currentmatrix def
+ x y tr xrad yrad sc 0 0 1 startangle endangle arc
+ closepath
+ savematrix setmatrix
+ } def
+
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+
+$F2psBegin
+%%Page: 1 1
+10 setmiterlimit
+ 0.06000 0.06000 sc
+% Polyline
+30.000 slw
+n 2174 2967 m 2179 2956 l 2183 2946 l 2189 2935 l 2195 2923 l 2202 2911 l
+ 2210 2898 l 2219 2886 l 2227 2873 l 2236 2861 l 2246 2848 l
+ 2254 2839 l 2262 2829 l 2270 2818 l 2280 2807 l 2289 2795 l
+ 2299 2783 l 2309 2770 l 2319 2756 l 2329 2743 l 2338 2730 l
+ 2347 2718 l 2355 2705 l 2362 2693 l 2369 2681 l 2374 2669 l
+ 2380 2657 l 2385 2644 l 2390 2631 l 2394 2617 l 2399 2603 l
+ 2403 2588 l 2406 2573 l 2410 2558 l 2414 2543 l 2417 2528 l
+ 2420 2513 l 2423 2498 l 2427 2484 l 2430 2469 l 2434 2453 l
+ 2439 2436 l 2443 2419 l 2448 2401 l 2452 2383 l 2457 2365 l
+ 2461 2347 l 2466 2329 l 2470 2313 l 2473 2297 l 2476 2282 l
+ 2479 2269 l 2481 2256 l 2483 2240 l 2485 2224 l 2485 2209 l
+ 2485 2194 l 2485 2180 l 2483 2167 l 2482 2155 l 2480 2143 l
+ 2478 2132 l 2476 2122 l 2474 2113 l 2472 2104 l 2470 2094 l
+ 2468 2083 l 2466 2071 l 2463 2059 l 2461 2046 l 2458 2032 l
+ 2456 2019 l 2453 2005 l 2450 1990 l 2448 1975 l 2445 1962 l
+ 2442 1947 l 2439 1932 l 2437 1916 l 2433 1898 l 2430 1880 l
+ 2427 1862 l 2424 1844 l 2421 1826 l 2419 1808 l 2416 1791 l
+ 2414 1775 l 2412 1760 l 2411 1746 l 2409 1730 l 2408 1715 l
+ 2407 1699 l 2406 1684 l 2406 1668 l 2407 1653 l 2408 1638 l
+ 2409 1624 l 2410 1610 l 2412 1597 l 2415 1584 l 2418 1571 l
+ 2421 1559 l 2424 1545 l 2428 1532 l 2432 1517 l 2437 1503 l
+ 2442 1489 l 2446 1475 l 2451 1462 l 2455 1450 l 2459 1439 l
+ 2463 1429 l 2466 1420 l 2469 1411 l 2472 1403 l 2475 1395 l
+ 2479 1386 l 2483 1378 l 2489 1369 l 2495 1359 l 2502 1349 l
+ 2511 1338 l 2521 1325 l 2529 1316 l 2537 1306 l 2546 1295 l
+ 2556 1283 l 2568 1270 l 2580 1255 l 2593 1241 l 2607 1225 l
+ 2621 1209 l 2636 1193 l 2651 1178 l 2665 1162 l 2680 1147 l
+ 2694 1132 l 2709 1117 l 2723 1103 l 2735 1091 l 2748 1078 l
+ 2762 1066 l 2775 1053 l 2789 1041 l 2804 1028 l 2819 1015 l
+ 2834 1002 l 2849 989 l 2864 976 l 2879 964 l 2894 951 l
+ 2909 940 l 2924 929 l 2938 918 l 2951 908 l 2964 898 l
+ 2978 889 l 2992 878 l 3008 868 l 3023 857 l 3039 847 l
+ 3055 836 l 3071 826 l 3088 815 l 3104 805 l 3121 795 l
+ 3136 786 l 3152 777 l 3167 768 l 3181 760 l 3194 753 l
+ 3207 746 l 3219 740 l 3234 731 l 3250 724 l 3265 716 l
+ 3281 709 l 3296 703 l 3311 697 l 3325 692 l 3339 688 l
+ 3351 685 l 3363 683 l 3374 682 l 3384 682 l 3393 683 l
+ 3402 684 l 3412 687 l 3420 690 l 3429 694 l 3436 698 l
+ 3443 703 l 3448 709 l 3453 715 l 3456 720 l 3457 726 l
+ 3458 732 l 3457 738 l 3455 745 l 3450 753 l 3444 761 l
+ 3437 770 l 3429 779 l 3419 788 l 3410 797 l 3400 805 l
+ 3391 815 l 3382 822 l 3374 831 l 3365 840 l 3355 850 l
+ 3345 860 l 3335 871 l 3325 882 l 3315 893 l 3305 904 l
+ 3296 915 l 3287 925 l 3278 936 l 3269 946 l 3260 957 l
+ 3251 969 l 3242 981 l 3232 993 l 3223 1005 l 3214 1017 l
+ 3205 1029 l 3197 1040 l 3189 1050 l 3182 1060 l 3176 1069 l
+ 3168 1080 l 3161 1090 l 3154 1100 l 3148 1110 l 3141 1120 l
+ 3136 1130 l 3131 1139 l 3126 1148 l 3123 1156 l 3120 1164 l
+ 3116 1174 l 3113 1185 l 3111 1196 l 3109 1209 l 3108 1221 l
+ 3107 1233 l 3106 1245 l 3106 1257 l 3106 1268 l 3107 1281 l
+ 3107 1294 l 3109 1308 l 3110 1321 l 3112 1334 l 3114 1345 l
+ 3117 1356 l 3120 1365 l 3124 1375 l 3128 1383 l 3133 1392 l
+ 3139 1399 l 3145 1405 l 3152 1410 l 3159 1414 l 3166 1416 l
+ 3175 1418 l 3185 1419 l 3196 1418 l 3208 1416 l 3221 1414 l
+ 3234 1410 l 3248 1405 l 3258 1401 l 3268 1397 l 3280 1392 l
+ 3292 1387 l 3305 1381 l 3319 1375 l 3334 1368 l 3348 1362 l
+ 3363 1356 l 3378 1350 l 3392 1344 l 3407 1339 l 3419 1334 l
+ 3432 1329 l 3446 1325 l 3461 1320 l 3476 1316 l 3492 1311 l
+ 3509 1307 l 3525 1303 l 3542 1299 l 3559 1296 l 3575 1292 l
+ 3591 1289 l 3607 1287 l 3622 1285 l 3638 1282 l 3654 1280 l
+ 3671 1279 l 3688 1277 l 3707 1275 l 3726 1274 l 3745 1273 l
+ 3764 1272 l 3784 1272 l 3803 1271 l 3822 1271 l 3840 1272 l
+ 3858 1272 l 3875 1273 l 3890 1273 l 3906 1274 l 3923 1275 l
+ 3940 1277 l 3958 1278 l 3976 1281 l 3996 1283 l 4016 1286 l
+ 4036 1289 l 4057 1293 l 4078 1297 l 4099 1301 l 4120 1306 l
+ 4141 1311 l 4162 1317 l 4183 1323 l 4201 1328 l 4219 1333 l
+ 4238 1339 l 4257 1345 l 4278 1352 l 4299 1359 l 4320 1366 l
+ 4342 1374 l 4364 1383 l 4386 1391 l 4408 1400 l 4430 1409 l
+ 4451 1417 l 4472 1426 l 4491 1435 l 4510 1443 l 4528 1452 l
+ 4545 1460 l 4561 1468 l 4576 1476 l 4596 1487 l 4616 1499 l
+ 4634 1511 l 4652 1523 l 4669 1535 l 4686 1547 l 4701 1560 l
+ 4715 1572 l 4728 1583 l 4740 1594 l 4751 1604 l 4760 1614 l
+ 4769 1623 l 4777 1631 l 4787 1642 l 4797 1653 l 4807 1663 l
+ 4817 1672 l 4827 1681 l 4836 1689 l 4846 1696 l 4855 1701 l
+ 4864 1705 l 4874 1709 l 4882 1711 l 4891 1712 l 4902 1713 l
+ 4913 1713 l 4925 1712 l 4938 1710 l 4952 1708 l 4966 1705 l
+ 4981 1701 l 4996 1697 l 5011 1692 l 5026 1686 l 5040 1681 l
+ 5055 1675 l 5070 1668 l 5086 1661 l 5103 1653 l 5120 1644 l
+ 5136 1636 l 5153 1627 l 5169 1618 l 5184 1609 l 5198 1601 l
+ 5210 1593 l 5221 1585 l 5231 1578 l 5241 1570 l 5250 1562 l
+ 5258 1553 l 5264 1545 l 5270 1536 l 5274 1526 l 5278 1516 l
+ 5280 1505 l 5282 1494 l 5283 1483 l 5284 1471 l 5284 1459 l
+ 5285 1447 l 5285 1434 l 5284 1420 l 5284 1405 l 5283 1388 l
+ 5282 1371 l 5281 1353 l 5279 1335 l 5277 1316 l 5274 1298 l
+ 5271 1280 l 5267 1263 l 5263 1246 l 5259 1230 l 5254 1214 l
+ 5248 1198 l 5241 1181 l 5234 1165 l 5227 1148 l 5219 1131 l
+ 5210 1115 l 5202 1098 l 5193 1083 l 5185 1069 l 5178 1055 l
+ 5170 1043 l 5164 1031 l 5158 1021 l 5150 1007 l 5143 993 l
+ 5136 981 l 5131 969 l 5126 957 l 5123 947 l 5121 938 l
+ 5120 929 l 5121 922 l 5122 916 l 5125 910 l 5129 905 l
+ 5135 899 l 5141 894 l 5149 890 l 5158 886 l 5167 883 l
+ 5177 880 l 5187 879 l 5197 878 l 5208 877 l 5219 877 l
+ 5232 878 l 5245 880 l 5259 883 l 5273 887 l 5287 891 l
+ 5300 896 l 5314 902 l 5326 908 l 5335 913 l 5345 918 l
+ 5354 925 l 5365 932 l 5375 940 l 5386 949 l 5398 958 l
+ 5410 969 l 5422 980 l 5434 992 l 5446 1004 l 5458 1016 l
+ 5470 1030 l 5482 1044 l 5492 1055 l 5502 1067 l 5513 1080 l
+ 5524 1093 l 5536 1108 l 5548 1123 l 5560 1139 l 5573 1155 l
+ 5585 1172 l 5598 1189 l 5610 1206 l 5622 1223 l 5633 1240 l
+ 5644 1256 l 5654 1272 l 5663 1287 l 5673 1302 l 5681 1317 l
+ 5690 1333 l 5699 1349 l 5707 1365 l 5715 1382 l 5723 1399 l
+ 5730 1416 l 5737 1434 l 5744 1451 l 5750 1468 l 5756 1485 l
+ 5762 1502 l 5767 1518 l 5771 1534 l 5776 1549 l 5780 1563 l
+ 5783 1578 l 5787 1592 l 5790 1607 l 5794 1622 l 5797 1637 l
+ 5800 1653 l 5804 1670 l 5806 1687 l 5809 1704 l 5811 1721 l
+ 5813 1738 l 5815 1754 l 5816 1771 l 5817 1786 l 5817 1802 l
+ 5817 1817 l 5816 1832 l 5815 1847 l 5814 1862 l 5812 1877 l
+ 5810 1893 l 5807 1910 l 5803 1928 l 5799 1945 l 5794 1964 l
+ 5788 1982 l 5782 2000 l 5775 2019 l 5768 2037 l 5760 2055 l
+ 5752 2072 l 5744 2089 l 5735 2107 l 5726 2122 l 5717 2138 l
+ 5707 2155 l 5697 2172 l 5686 2190 l 5674 2208 l 5661 2227 l
+ 5647 2245 l 5634 2264 l 5619 2283 l 5605 2302 l 5590 2320 l
+ 5576 2338 l 5561 2355 l 5547 2371 l 5532 2387 l 5518 2402 l
+ 5504 2417 l 5490 2431 l 5475 2445 l 5460 2458 l 5445 2472 l
+ 5429 2486 l 5412 2500 l 5396 2514 l 5379 2527 l 5362 2540 l
+ 5346 2553 l 5330 2566 l 5314 2577 l 5299 2589 l 5284 2599 l
+ 5270 2609 l 5257 2618 l 5245 2627 l 5233 2636 l 5216 2648 l
+ 5199 2659 l 5183 2671 l 5168 2681 l 5153 2692 l 5139 2701 l
+ 5126 2710 l 5115 2718 l 5105 2724 l 5097 2730 l 5090 2734 l
+ 5085 2737 l 5081 2739 l 5078 2741 l 5075 2743 l 5073 2744 l
+ 5072 2746 l 5071 2747 l 5070 2750 l 5070 2753 l 5070 2756 l
+ 5071 2761 l 5071 2766 l 5072 2772 l 5073 2780 l 5073 2789 l
+ 5074 2798 l 5074 2809 l 5074 2821 l 5074 2834 l 5074 2849 l
+ 5074 2865 l 5073 2883 l 5073 2901 l 5072 2921 l 5070 2940 l
+ 5069 2960 l 5067 2979 l 5066 2999 l 5064 3018 l 5061 3036 l
+ 5059 3055 l 5056 3073 l 5053 3092 l 5050 3111 l 5046 3130 l
+ 5042 3150 l 5037 3170 l 5032 3190 l 5026 3211 l 5021 3231 l
+ 5015 3251 l 5008 3270 l 5002 3289 l 4996 3307 l 4989 3324 l
+ 4982 3340 l 4976 3356 l 4968 3372 l 4961 3387 l 4953 3403 l
+ 4944 3419 l 4935 3436 l 4925 3452 l 4915 3469 l 4904 3486 l
+ 4893 3503 l 4882 3519 l 4870 3535 l 4859 3550 l 4847 3565 l
+ 4835 3580 l 4823 3594 l 4812 3608 l 4799 3622 l 4786 3636 l
+ 4773 3650 l 4759 3665 l 4744 3680 l 4730 3695 l 4714 3710 l
+ 4699 3726 l 4684 3741 l 4670 3756 l 4656 3770 l 4643 3783 l
+ 4630 3796 l 4619 3808 l 4608 3819 l 4599 3830 l 4587 3843 l
+ 4576 3856 l 4565 3869 l 4556 3882 l 4547 3895 l 4539 3907 l
+ 4532 3919 l 4526 3930 l 4521 3941 l 4517 3951 l 4513 3961 l
+ 4510 3970 l 4506 3981 l 4503 3992 l 4501 4004 l 4498 4016 l
+ 4496 4029 l 4494 4042 l 4493 4054 l 4493 4066 l 4493 4078 l
+ 4493 4089 l 4493 4100 l 4494 4112 l 4496 4124 l 4498 4137 l
+ 4501 4150 l 4504 4164 l 4507 4177 l 4511 4189 l 4515 4200 l
+ 4520 4212 l 4525 4223 l 4530 4234 l 4537 4246 l 4543 4259 l
+ 4551 4272 l 4558 4284 l 4565 4297 l 4572 4309 l 4579 4320 l
+ 4585 4331 l 4591 4343 l 4597 4354 l 4603 4367 l 4609 4380 l
+ 4615 4394 l 4621 4408 l 4626 4422 l 4631 4436 l 4636 4450 l
+ 4640 4464 l 4643 4474 l 4646 4485 l 4649 4496 l 4652 4508 l
+ 4654 4521 l 4657 4534 l 4660 4549 l 4663 4563 l 4665 4579 l
+ 4667 4594 l 4669 4610 l 4671 4625 l 4673 4641 l 4675 4658 l
+ 4676 4672 l 4677 4688 l 4678 4704 l 4679 4721 l 4680 4739 l
+ 4681 4757 l 4682 4776 l 4682 4795 l 4683 4814 l 4683 4832 l
+ 4683 4851 l 4684 4868 l 4684 4884 l 4683 4900 l 4683 4915 l
+ 4683 4929 l 4682 4946 l 4682 4963 l 4681 4980 l 4679 4996 l
+ 4678 5012 l 4676 5028 l 4674 5043 l 4671 5056 l 4669 5069 l
+ 4666 5081 l 4663 5092 l 4661 5103 l 4657 5115 l 4652 5128 l
+ 4648 5141 l 4643 5154 l 4638 5168 l 4633 5181 l 4628 5194 l
+ 4624 5206 l 4621 5218 l 4618 5229 l 4616 5238 l 4615 5247 l
+ 4614 5257 l 4613 5268 l 4613 5280 l 4614 5292 l 4616 5305 l
+ 4618 5319 l 4620 5334 l 4624 5349 l 4628 5365 l 4632 5382 l
+ 4636 5395 l 4640 5410 l 4645 5425 l 4650 5442 l 4656 5460 l
+ 4663 5479 l 4670 5498 l 4677 5519 l 4685 5540 l 4693 5560 l
+ 4702 5581 l 4710 5602 l 4719 5621 l 4728 5641 l 4737 5660 l
+ 4746 5678 l 4754 5694 l 4762 5711 l 4771 5727 l 4780 5744 l
+ 4790 5762 l 4801 5779 l 4812 5797 l 4823 5814 l 4834 5832 l
+ 4846 5849 l 4859 5866 l 4871 5883 l 4883 5899 l 4895 5914 l
+ 4908 5929 l 4920 5943 l 4932 5957 l 4944 5970 l 4957 5983 l
+ 4970 5996 l 4984 6009 l 4998 6021 l 5013 6034 l 5028 6048 l
+ 5044 6061 l 5061 6074 l 5078 6087 l 5095 6099 l 5113 6112 l
+ 5130 6124 l 5147 6135 l 5164 6146 l 5181 6156 l 5198 6167 l
+ 5214 6176 l 5230 6186 l 5247 6195 l 5264 6204 l 5281 6213 l
+ 5299 6222 l 5318 6232 l 5337 6241 l 5357 6250 l 5378 6260 l
+ 5399 6269 l 5420 6278 l 5441 6287 l 5462 6295 l 5483 6303 l
+ 5503 6311 l 5523 6318 l 5543 6325 l 5563 6332 l 5582 6338 l
+ 5600 6344 l 5618 6350 l 5637 6355 l 5656 6361 l 5676 6366 l
+ 5697 6372 l 5718 6377 l 5740 6383 l 5762 6389 l 5785 6394 l
+ 5807 6400 l 5830 6405 l 5853 6410 l 5875 6416 l 5898 6421 l
+ 5919 6425 l 5941 6430 l 5962 6435 l 5983 6439 l 6004 6444 l
+ 6025 6448 l 6046 6453 l 6068 6457 l 6090 6462 l 6113 6467 l
+ 6136 6472 l 6160 6477 l 6185 6482 l 6209 6487 l 6233 6492 l
+ 6258 6497 l 6282 6502 l 6305 6507 l 6328 6512 l 6350 6517 l
+ 6371 6522 l 6391 6526 l 6411 6531 l 6430 6535 l 6448 6539 l
+ 6470 6544 l 6491 6549 l 6513 6555 l 6535 6560 l 6556 6565 l
+ 6578 6571 l 6599 6576 l 6620 6582 l 6640 6587 l 6659 6593 l
+ 6678 6598 l 6695 6603 l 6712 6608 l 6727 6613 l 6742 6618 l
+ 6756 6622 l 6772 6627 l 6788 6632 l 6803 6638 l 6819 6643 l
+ 6835 6649 l 6851 6655 l 6867 6662 l 6882 6668 l 6897 6674 l
+ 6912 6681 l 6925 6687 l 6938 6694 l 6951 6700 l 6963 6707 l
+ 6975 6713 l 6987 6721 l 7000 6728 l 7012 6736 l 7025 6745 l
+ 7038 6754 l 7051 6763 l 7063 6773 l 7075 6783 l 7086 6792 l
+ 7096 6802 l 7106 6811 l 7115 6820 l 7123 6829 l 7132 6840 l
+ 7140 6851 l 7148 6863 l 7156 6875 l 7163 6888 l 7170 6901 l
+ 7176 6914 l 7181 6927 l 7186 6940 l 7189 6951 l 7193 6963 l
+ 7196 6974 l 7198 6987 l 7200 7000 l 7202 7014 l 7203 7029 l
+ 7202 7043 l 7201 7058 l 7198 7072 l 7194 7086 l 7189 7099 l
+ 7183 7111 l 7177 7122 l 7170 7132 l 7162 7144 l 7153 7155 l
+ 7143 7167 l 7132 7179 l 7120 7190 l 7108 7201 l 7097 7211 l
+ 7085 7221 l 7074 7230 l 7063 7238 l 7054 7245 l 7044 7252 l
+ 7034 7258 l 7023 7265 l 7012 7271 l 6999 7277 l 6986 7284 l
+ 6973 7290 l 6958 7295 l 6943 7301 l 6928 7306 l 6912 7311 l
+ 6895 7316 l 6878 7321 l 6862 7325 l 6844 7330 l 6826 7334 l
+ 6806 7339 l 6786 7343 l 6764 7348 l 6742 7352 l 6720 7357 l
+ 6699 7361 l 6677 7366 l 6657 7370 l 6638 7373 l 6620 7377 l
+ 6604 7380 l 6589 7383 l 6576 7385 l 6560 7388 l 6546 7391 l
+ 6534 7393 l 6524 7396 l 6515 7398 l 6507 7400 l 6502 7403 l
+ 6498 7405 l 6495 7408 l 6493 7411 l 6493 7414 l 6493 7417 l
+ 6494 7425 l 6496 7436 l 6499 7448 l 6502 7460 l 6504 7471 l
+ 6504 7480 l 6502 7484 l 6500 7487 l 6497 7491 l 6491 7493 l
+ 6484 7495 l 6475 7497 l 6464 7499 l 6450 7500 l 6435 7500 l
+ 6418 7501 l 6408 7501 l 6396 7502 l 6384 7502 l 6370 7502 l
+ 6355 7502 l 6338 7503 l 6321 7503 l 6302 7503 l 6282 7504 l
+ 6262 7504 l 6241 7505 l 6219 7505 l 6198 7505 l 6176 7506 l
+ 6154 7506 l 6131 7507 l 6109 7507 l 6087 7508 l 6066 7509 l
+ 6044 7509 l 6022 7510 l 5999 7511 l 5975 7511 l 5951 7512 l
+ 5925 7513 l 5900 7514 l 5873 7515 l 5847 7516 l 5821 7517 l
+ 5795 7518 l 5770 7519 l 5745 7520 l 5722 7521 l 5699 7522 l
+ 5677 7523 l 5656 7524 l 5636 7525 l 5617 7526 l 5594 7527 l
+ 5571 7528 l 5549 7530 l 5528 7531 l 5506 7532 l 5485 7533 l
+ 5465 7535 l 5446 7536 l 5428 7537 l 5410 7538 l 5394 7539 l
+ 5380 7539 l 5367 7540 l 5355 7540 l 5344 7541 l 5334 7541 l
+ 5320 7541 l 5307 7541 l 5296 7540 l 5286 7539 l 5277 7538 l
+ 5270 7536 l 5266 7534 l 5262 7532 l 5261 7530 l 5260 7527 l
+ 5260 7525 l 5262 7522 l 5265 7518 l 5270 7514 l 5277 7508 l
+ 5286 7502 l 5298 7494 l 5313 7485 l 5330 7474 l 5350 7462 l
+ 5373 7449 l 5399 7435 l 5414 7426 l 5431 7417 l 5449 7407 l
+ 5468 7396 l 5488 7385 l 5510 7373 l 5533 7361 l 5556 7348 l
+ 5581 7334 l 5606 7321 l 5632 7306 l 5657 7292 l 5683 7278 l
+ 5708 7264 l 5733 7251 l 5758 7237 l 5781 7224 l 5804 7212 l
+ 5825 7200 l 5846 7189 l 5865 7178 l 5884 7168 l 5908 7154 l
+ 5932 7141 l 5954 7128 l 5975 7116 l 5996 7104 l 6016 7092 l
+ 6035 7081 l 6052 7071 l 6069 7061 l 6084 7052 l 6098 7043 l
+ 6111 7035 l 6122 7028 l 6133 7021 l 6142 7015 l 6151 7010 l
+ 6163 7001 l 6175 6993 l 6187 6985 l 6197 6977 l 6207 6971 l
+ 6217 6965 l 6225 6961 l 6232 6958 l 6238 6956 l 6244 6956 l
+ 6249 6956 l 6254 6957 l 6259 6960 l 6264 6964 l 6269 6968 l
+ 6274 6974 l 6279 6980 l 6284 6986 l 6288 6992 l 6293 6999 l
+ 6298 7007 l 6304 7016 l 6310 7026 l 6316 7036 l 6322 7046 l
+ 6328 7057 l 6333 7066 l 6338 7076 l 6342 7085 l 6346 7095 l
+ 6351 7105 l 6355 7115 l 6359 7125 l 6363 7134 l 6367 7142 l
+ 6370 7150 l 6373 7156 l 6377 7162 l 6381 7167 l 6386 7172 l
+ 6392 7177 l 6399 7182 l 6406 7185 l 6415 7188 l 6424 7190 l
+ 6435 7191 l 6444 7191 l 6455 7191 l 6467 7190 l 6481 7189 l
+ 6495 7187 l 6510 7185 l 6526 7183 l 6542 7180 l 6557 7177 l
+ 6572 7173 l 6586 7170 l 6599 7167 l 6613 7163 l 6626 7159 l
+ 6639 7155 l 6653 7151 l 6667 7146 l 6680 7141 l 6694 7136 l
+ 6706 7131 l 6719 7126 l 6730 7121 l 6741 7116 l 6752 7111 l
+ 6764 7104 l 6776 7098 l 6789 7090 l 6801 7083 l 6813 7075 l
+ 6825 7066 l 6835 7058 l 6844 7050 l 6851 7043 l 6857 7036 l
+ 6861 7030 l 6864 7024 l 6867 7017 l 6869 7010 l 6870 7004 l
+ 6870 6996 l 6869 6989 l 6867 6982 l 6865 6975 l 6862 6968 l
+ 6858 6961 l 6853 6954 l 6848 6947 l 6842 6939 l 6835 6931 l
+ 6826 6923 l 6817 6914 l 6807 6905 l 6796 6896 l 6784 6888 l
+ 6773 6879 l 6761 6871 l 6748 6864 l 6736 6857 l 6726 6852 l
+ 6716 6847 l 6705 6842 l 6694 6837 l 6681 6831 l 6667 6826 l
+ 6652 6821 l 6636 6816 l 6620 6811 l 6602 6806 l 6584 6801 l
+ 6565 6797 l 6546 6792 l 6526 6788 l 6506 6784 l 6485 6780 l
+ 6467 6777 l 6448 6774 l 6428 6770 l 6407 6767 l 6384 6764 l
+ 6361 6760 l 6337 6757 l 6312 6753 l 6286 6749 l 6259 6746 l
+ 6232 6742 l 6206 6738 l 6179 6735 l 6153 6731 l 6127 6728 l
+ 6102 6724 l 6078 6721 l 6054 6717 l 6031 6714 l 6009 6711 l
+ 5986 6707 l 5964 6704 l 5942 6700 l 5920 6696 l 5897 6693 l
+ 5874 6689 l 5851 6685 l 5828 6681 l 5805 6676 l 5783 6672 l
+ 5760 6668 l 5738 6664 l 5717 6660 l 5696 6655 l 5676 6651 l
+ 5657 6647 l 5639 6644 l 5622 6640 l 5605 6636 l 5588 6633 l
+ 5568 6628 l 5547 6623 l 5527 6619 l 5507 6614 l 5486 6609 l
+ 5465 6603 l 5444 6598 l 5423 6593 l 5402 6587 l 5382 6582 l
+ 5363 6577 l 5344 6571 l 5326 6566 l 5309 6561 l 5292 6557 l
+ 5276 6552 l 5260 6547 l 5243 6542 l 5227 6537 l 5210 6531 l
+ 5192 6526 l 5175 6520 l 5157 6514 l 5140 6508 l 5122 6502 l
+ 5105 6496 l 5089 6491 l 5073 6485 l 5058 6480 l 5044 6475 l
+ 5030 6470 l 5017 6465 l 5003 6460 l 4988 6454 l 4974 6449 l
+ 4959 6443 l 4944 6437 l 4929 6431 l 4915 6425 l 4900 6419 l
+ 4887 6413 l 4873 6407 l 4861 6401 l 4849 6395 l 4838 6389 l
+ 4827 6383 l 4814 6375 l 4801 6368 l 4788 6360 l 4775 6351 l
+ 4762 6342 l 4748 6333 l 4735 6324 l 4722 6315 l 4710 6306 l
+ 4698 6298 l 4687 6290 l 4676 6283 l 4666 6275 l 4655 6268 l
+ 4644 6260 l 4633 6252 l 4621 6244 l 4610 6236 l 4598 6227 l
+ 4587 6219 l 4577 6211 l 4566 6203 l 4557 6195 l 4547 6187 l
+ 4536 6177 l 4525 6167 l 4513 6156 l 4501 6145 l 4490 6133 l
+ 4478 6123 l 4467 6113 l 4457 6105 l 4448 6098 l 4440 6093 l
+ 4433 6089 l 4427 6086 l 4419 6085 l 4410 6084 l 4400 6086 l
+ 4388 6088 l 4373 6092 l 4356 6097 l 4337 6104 l 4316 6113 l
+ 4292 6122 l 4265 6133 l 4250 6139 l 4234 6146 l 4217 6153 l
+ 4198 6160 l 4179 6167 l 4158 6175 l 4136 6183 l 4112 6191 l
+ 4088 6199 l 4062 6207 l 4036 6215 l 4009 6223 l 3982 6230 l
+ 3954 6237 l 3926 6243 l 3897 6248 l 3869 6253 l 3841 6257 l
+ 3814 6261 l 3787 6263 l 3760 6265 l 3733 6265 l 3707 6265 l
+ 3681 6264 l 3655 6261 l 3629 6258 l 3603 6254 l 3577 6248 l
+ 3550 6242 l 3523 6235 l 3496 6227 l 3469 6218 l 3441 6208 l
+ 3414 6198 l 3387 6187 l 3361 6176 l 3335 6165 l 3310 6153 l
+ 3286 6141 l 3263 6130 l 3242 6118 l 3221 6107 l 3201 6096 l
+ 3183 6085 l 3166 6075 l 3151 6066 l 3136 6057 l 3123 6048 l
+ 3102 6035 l 3083 6022 l 3067 6011 l 3052 6000 l 3039 5990 l
+ 3028 5980 l 3019 5971 l 3010 5963 l 3003 5955 l 2997 5947 l
+ 2992 5939 l 2987 5932 l 2982 5924 l 2977 5916 l 2972 5907 l
+ 2966 5897 l 2959 5886 l 2952 5874 l 2944 5862 l 2936 5849 l
+ 2927 5835 l 2918 5821 l 2910 5807 l 2902 5793 l 2894 5780 l
+ 2886 5767 l 2879 5755 l 2873 5744 l 2865 5730 l 2858 5717 l
+ 2852 5704 l 2845 5690 l 2839 5676 l 2834 5663 l 2828 5649 l
+ 2824 5636 l 2820 5624 l 2816 5612 l 2813 5600 l 2811 5589 l
+ 2809 5578 l 2807 5566 l 2805 5554 l 2804 5541 l 2803 5528 l
+ 2802 5515 l 2801 5502 l 2801 5489 l 2801 5477 l 2801 5465 l
+ 2802 5454 l 2802 5444 l 2803 5431 l 2805 5418 l 2806 5406 l
+ 2808 5392 l 2810 5379 l 2813 5366 l 2816 5354 l 2819 5343 l
+ 2822 5332 l 2825 5322 l 2830 5309 l 2835 5297 l 2840 5284 l
+ 2846 5271 l 2852 5259 l 2857 5248 l 2862 5239 l 2866 5231 l
+ 2870 5221 l 2874 5212 l 2876 5205 l 2877 5197 l 2878 5191 l
+ 2877 5186 l 2875 5181 l 2872 5175 l 2867 5168 l 2862 5161 l
+ 2855 5154 l 2848 5146 l 2841 5139 l 2834 5131 l 2826 5122 l
+ 2817 5113 l 2809 5103 l 2802 5093 l 2795 5083 l 2789 5074 l
+ 2785 5064 l 2781 5054 l 2778 5043 l 2775 5032 l 2774 5022 l
+ 2773 5012 l 2773 5003 l 2774 4995 l 2774 4988 l 2776 4981 l
+ 2777 4974 l 2778 4968 l 2778 4962 l 2777 4957 l 2775 4953 l
+ 2772 4951 l 2766 4948 l 2756 4945 l 2745 4944 l 2732 4942 l
+ 2720 4941 l 2709 4940 l 2700 4938 l 2691 4936 l 2682 4933 l
+ 2675 4929 l 2668 4925 l 2663 4921 l 2658 4916 l 2652 4910 l
+ 2647 4904 l 2641 4898 l 2635 4892 l 2628 4888 l 2624 4885 l
+ 2620 4882 l 2614 4878 l 2607 4873 l 2599 4866 l 2589 4857 l
+ 2578 4846 l 2565 4832 l 2551 4816 l 2536 4796 l 2526 4784 l
+ 2516 4770 l 2505 4755 l 2493 4739 l 2481 4722 l 2469 4703 l
+ 2456 4683 l 2443 4663 l 2431 4643 l 2418 4622 l 2407 4601 l
+ 2396 4580 l 2386 4561 l 2377 4542 l 2369 4524 l 2363 4507 l
+ 2358 4491 l 2354 4476 l 2352 4463 l 2351 4451 l 2351 4439 l
+ 2352 4428 l 2354 4417 l 2357 4407 l 2361 4397 l 2366 4388 l
+ 2372 4379 l 2379 4370 l 2387 4362 l 2395 4355 l 2404 4348 l
+ 2414 4342 l 2424 4337 l 2434 4331 l 2445 4327 l 2455 4323 l
+ 2466 4319 l 2477 4315 l 2492 4311 l 2507 4307 l 2522 4304 l
+ 2539 4301 l 2556 4298 l 2574 4295 l 2592 4292 l 2611 4290 l
+ 2630 4288 l 2649 4287 l 2668 4285 l 2686 4284 l 2703 4284 l
+ 2720 4283 l 2736 4283 l 2752 4283 l 2769 4284 l 2787 4284 l
+ 2805 4285 l 2823 4286 l 2841 4287 l 2860 4289 l 2878 4291 l
+ 2895 4292 l 2912 4294 l 2928 4296 l 2943 4298 l 2957 4300 l
+ 2970 4302 l 2983 4304 l 2999 4306 l 3015 4308 l 3030 4311 l
+ 3046 4312 l 3061 4314 l 3075 4314 l 3088 4314 l 3099 4313 l
+ 3110 4311 l 3119 4308 l 3128 4304 l 3137 4299 l 3146 4292 l
+ 3155 4285 l 3163 4276 l 3170 4267 l 3177 4257 l 3183 4248 l
+ 3188 4238 l 3193 4229 l 3196 4219 l 3200 4209 l 3203 4199 l
+ 3205 4188 l 3207 4177 l 3208 4166 l 3208 4155 l 3208 4145 l
+ 3208 4135 l 3207 4126 l 3205 4114 l 3201 4102 l 3197 4090 l
+ 3192 4078 l 3186 4066 l 3179 4056 l 3172 4046 l 3165 4039 l
+ 3157 4031 l 3147 4025 l 3137 4019 l 3126 4013 l 3114 4007 l
+ 3102 4002 l 3091 3997 l 3081 3992 l 3072 3988 l 3063 3984 l
+ 3053 3979 l 3043 3974 l 3033 3969 l 3023 3963 l 3013 3957 l
+ 3003 3950 l 2993 3944 l 2984 3938 l 2975 3931 l 2965 3923 l
+ 2955 3915 l 2943 3906 l 2932 3897 l 2920 3888 l 2908 3879 l
+ 2896 3870 l 2885 3861 l 2873 3853 l 2863 3846 l 2853 3840 l
+ 2842 3833 l 2831 3826 l 2819 3818 l 2807 3811 l 2795 3804 l
+ 2783 3797 l 2771 3790 l 2761 3784 l 2751 3777 l 2741 3772 l
+ 2730 3764 l 2719 3757 l 2707 3750 l 2696 3743 l 2684 3735 l
+ 2672 3728 l 2660 3721 l 2649 3715 l 2638 3710 l 2627 3705 l
+ 2618 3701 l 2608 3697 l 2597 3693 l 2586 3689 l 2574 3685 l
+ 2562 3681 l 2550 3677 l 2537 3672 l 2525 3668 l 2513 3663 l
+ 2501 3659 l 2490 3654 l 2478 3649 l 2466 3643 l 2454 3636 l
+ 2441 3629 l 2428 3621 l 2414 3613 l 2401 3604 l 2388 3595 l
+ 2375 3585 l 2363 3576 l 2352 3567 l 2342 3557 l 2331 3547 l
+ 2321 3537 l 2311 3526 l 2300 3514 l 2290 3502 l 2280 3490 l
+ 2270 3477 l 2261 3465 l 2252 3454 l 2244 3443 l 2237 3433 l
+ 2231 3424 l 2223 3413 l 2216 3402 l 2209 3391 l 2202 3380 l
+ 2195 3368 l 2189 3357 l 2184 3346 l 2178 3335 l 2174 3325 l
+ 2170 3314 l 2166 3303 l 2162 3291 l 2158 3278 l 2154 3265 l
+ 2151 3251 l 2148 3237 l 2145 3223 l 2142 3211 l 2141 3199 l
+ 2139 3188 l 2138 3177 l 2137 3166 l 2136 3156 l 2136 3145 l
+ 2136 3133 l 2136 3122 l 2137 3112 l 2138 3101 l 2140 3092 l
+ 2141 3082 l 2143 3072 l 2145 3061 l 2148 3049 l 2151 3037 l
+ 2154 3025 l 2158 3012 l 2162 3000 l 2166 2988 l 2170 2977 l
+
+ cp gs col20 1.00 shd ef gr gs col0 s gr
+% Polyline
+n 2420 6449 m 2432 6448 l 2444 6448 l 2457 6447 l 2471 6446 l 2484 6446 l
+ 2498 6445 l 2511 6445 l 2524 6445 l 2536 6445 l 2548 6445 l
+ 2560 6444 l 2572 6444 l 2584 6444 l 2597 6444 l 2610 6444 l
+ 2623 6444 l 2635 6444 l 2647 6444 l 2658 6444 l 2669 6444 l
+ 2679 6443 l 2689 6443 l 2700 6443 l 2711 6442 l 2722 6441 l
+ 2733 6440 l 2743 6439 l 2752 6437 l 2761 6435 l 2770 6433 l
+ 2780 6429 l 2790 6424 l 2801 6419 l 2812 6413 l 2822 6407 l
+ 2833 6401 l 2843 6396 l 2854 6391 l 2864 6386 l 2875 6382 l
+ 2887 6377 l 2900 6372 l 2913 6368 l 2925 6364 l 2936 6360 l
+ 2947 6356 l 2957 6352 l 2967 6348 l 2977 6344 l 2987 6339 l
+ 2997 6335 l 3006 6330 l 3013 6326 l 3021 6323 l 3029 6318 l
+ 3037 6312 l 3045 6306 l 3051 6300 l 3056 6292 l 3060 6285 l
+ 3061 6278 l 3062 6270 l 3062 6261 l 3062 6251 l 3061 6241 l
+ 3059 6232 l 3057 6223 l 3055 6215 l 3052 6207 l 3049 6198 l
+ 3046 6190 l 3042 6181 l 3038 6173 l 3034 6164 l 3030 6156 l
+ 3027 6148 l 3023 6139 l 3019 6129 l 3015 6119 l 3011 6108 l
+ 3008 6096 l 3004 6086 l 3001 6075 l 2999 6066 l 2995 6054 l
+ 2992 6041 l 2990 6029 l 2989 6018 l 2989 6009 l 2990 6003 l
+ 2991 6000 l 2992 5998 l 2995 5996 l 2997 5994 l 3001 5994 l
+ 3004 5993 l 3008 5994 l 3012 5995 l 3017 5996 l 3021 5998 l
+ 3029 6001 l 3037 6006 l 3047 6012 l 3057 6018 l 3065 6025 l
+ 3073 6031 l 3080 6038 l 3088 6044 l 3095 6051 l 3103 6057 l
+ 3110 6062 l 3118 6065 l 3126 6066 l 3136 6066 l 3147 6065 l
+ 3158 6064 l 3169 6062 l 3180 6061 l 3188 6060 l 3197 6059 l
+ 3206 6059 l 3215 6059 l 3224 6059 l 3233 6059 l 3241 6060 l
+ 3249 6060 l 3258 6060 l 3268 6061 l 3279 6062 l 3289 6064 l
+ 3297 6066 l 3305 6068 l 3312 6071 l 3320 6075 l 3327 6081 l
+ 3335 6087 l 3342 6093 l 3348 6100 l 3355 6106 l 3362 6114 l
+ 3370 6122 l 3378 6129 l 3387 6134 l 3395 6138 l 3404 6140 l
+ 3413 6140 l 3424 6140 l 3434 6138 l 3443 6137 l 3452 6136 l
+ 3460 6135 l 3468 6134 l 3477 6135 l 3484 6137 l 3491 6139 l
+ 3496 6143 l 3501 6148 l 3505 6154 l 3510 6162 l 3514 6171 l
+ 3517 6180 l 3520 6189 l 3522 6196 l 3524 6204 l 3526 6212 l
+ 3528 6221 l 3530 6229 l 3532 6238 l 3533 6245 l 3534 6253 l
+ 3535 6262 l 3536 6271 l 3538 6279 l 3539 6285 l 3541 6288 l
+ 3543 6288 l 3545 6285 l 3548 6279 l 3552 6270 l 3556 6259 l
+ 3560 6247 l 3564 6236 l 3567 6227 l 3571 6218 l 3574 6208 l
+ 3578 6198 l 3582 6188 l 3586 6178 l 3590 6169 l 3594 6161 l
+ 3598 6152 l 3602 6143 l 3607 6134 l 3612 6126 l 3617 6117 l
+ 3623 6109 l 3628 6103 l 3634 6097 l 3639 6091 l 3646 6086 l
+ 3653 6081 l 3661 6076 l 3670 6072 l 3678 6069 l 3686 6066 l
+ 3694 6064 l 3701 6062 l 3710 6060 l 3719 6059 l 3728 6058 l
+ 3737 6057 l 3746 6057 l 3755 6057 l 3763 6058 l 3770 6058 l
+ 3778 6059 l 3787 6061 l 3795 6063 l 3804 6065 l 3812 6068 l
+ 3820 6070 l 3828 6074 l 3835 6077 l 3843 6081 l 3851 6086 l
+ 3860 6091 l 3869 6096 l 3877 6102 l 3885 6107 l 3893 6112 l
+ 3900 6117 l 3908 6123 l 3916 6129 l 3924 6135 l 3931 6141 l
+ 3938 6147 l 3944 6153 l 3950 6159 l 3956 6166 l 3962 6173 l
+ 3967 6179 l 3971 6184 l 3974 6188 l 3977 6189 l 3979 6187 l
+ 3981 6182 l 3983 6175 l 3986 6168 l 3989 6161 l 3992 6157 l
+ 3995 6154 l 3999 6151 l 4004 6148 l 4010 6146 l 4016 6144 l
+ 4023 6142 l 4030 6141 l 4038 6140 l 4046 6139 l 4056 6139 l
+ 4067 6138 l 4078 6138 l 4089 6138 l 4099 6137 l 4110 6137 l
+ 4120 6137 l 4131 6136 l 4142 6135 l 4154 6134 l 4166 6133 l
+ 4177 6132 l 4188 6130 l 4198 6128 l 4208 6126 l 4218 6123 l
+ 4229 6120 l 4240 6117 l 4251 6113 l 4261 6110 l 4271 6107 l
+ 4280 6104 l 4288 6101 l 4296 6098 l 4305 6095 l 4314 6091 l
+ 4323 6088 l 4332 6085 l 4340 6081 l 4348 6078 l 4356 6074 l
+ 4365 6071 l 4374 6067 l 4383 6064 l 4392 6062 l 4401 6062 l
+ 4409 6063 l 4416 6066 l 4423 6070 l 4429 6077 l 4436 6086 l
+ 4443 6097 l 4450 6109 l 4456 6122 l 4462 6134 l 4468 6147 l
+ 4473 6157 l 4478 6168 l 4483 6180 l 4489 6192 l 4495 6205 l
+ 4501 6218 l 4507 6231 l 4513 6243 l 4518 6255 l 4524 6267 l
+ 4528 6277 l 4533 6287 l 4537 6298 l 4542 6310 l 4548 6321 l
+ 4553 6334 l 4558 6346 l 4563 6358 l 4567 6370 l 4572 6381 l
+ 4576 6392 l 4580 6403 l 4584 6414 l 4588 6425 l 4592 6437 l
+ 4596 6449 l 4600 6461 l 4604 6474 l 4608 6486 l 4611 6498 l
+ 4615 6510 l 4618 6521 l 4622 6531 l 4625 6542 l 4629 6553 l
+ 4633 6565 l 4637 6578 l 4641 6590 l 4645 6602 l 4649 6614 l
+ 4653 6625 l 4657 6635 l 4660 6644 l 4663 6653 l 4665 6660 l
+ 4667 6668 l 4669 6675 l 4670 6682 l 4670 6690 l 4669 6698 l
+ 4667 6705 l 4663 6713 l 4659 6720 l 4653 6728 l 4647 6734 l
+ 4641 6740 l 4633 6747 l 4625 6755 l 4614 6763 l 4602 6771 l
+ 4589 6781 l 4574 6790 l 4558 6800 l 4540 6810 l 4522 6820 l
+ 4503 6831 l 4482 6841 l 4461 6852 l 4447 6858 l 4431 6866 l
+ 4415 6873 l 4398 6880 l 4380 6888 l 4361 6896 l 4341 6905 l
+ 4320 6913 l 4299 6922 l 4276 6931 l 4253 6940 l 4230 6949 l
+ 4206 6957 l 4183 6966 l 4159 6974 l 4136 6982 l 4112 6990 l
+ 4089 6997 l 4067 7004 l 4045 7011 l 4022 7018 l 4001 7024 l
+ 3979 7030 l 3956 7036 l 3934 7042 l 3910 7047 l 3887 7053 l
+ 3862 7058 l 3837 7063 l 3812 7068 l 3786 7073 l 3759 7078 l
+ 3732 7083 l 3705 7087 l 3679 7091 l 3652 7095 l 3625 7098 l
+ 3599 7102 l 3573 7105 l 3547 7107 l 3522 7110 l 3497 7112 l
+ 3473 7114 l 3448 7116 l 3425 7118 l 3402 7119 l 3378 7120 l
+ 3354 7121 l 3330 7122 l 3305 7123 l 3279 7124 l 3253 7125 l
+ 3226 7125 l 3199 7125 l 3172 7126 l 3146 7126 l 3119 7125 l
+ 3092 7125 l 3066 7125 l 3041 7124 l 3016 7123 l 2992 7123 l
+ 2969 7122 l 2947 7121 l 2925 7119 l 2904 7118 l 2884 7117 l
+ 2865 7115 l 2839 7113 l 2814 7110 l 2790 7107 l 2765 7104 l
+ 2741 7101 l 2717 7097 l 2693 7092 l 2669 7087 l 2646 7082 l
+ 2624 7077 l 2603 7071 l 2582 7065 l 2563 7058 l 2545 7051 l
+ 2527 7044 l 2511 7037 l 2496 7030 l 2481 7022 l 2467 7014 l
+ 2453 7005 l 2438 6996 l 2424 6986 l 2410 6975 l 2396 6964 l
+ 2382 6952 l 2368 6939 l 2354 6926 l 2340 6913 l 2326 6899 l
+ 2313 6885 l 2300 6872 l 2288 6858 l 2276 6844 l 2264 6831 l
+ 2252 6817 l 2241 6804 l 2228 6788 l 2215 6772 l 2202 6755 l
+ 2188 6738 l 2175 6721 l 2162 6703 l 2149 6685 l 2137 6667 l
+ 2127 6650 l 2117 6633 l 2109 6617 l 2102 6602 l 2098 6588 l
+ 2094 6575 l 2093 6564 l 2094 6553 l 2096 6542 l 2101 6532 l
+ 2108 6523 l 2118 6514 l 2129 6506 l 2142 6499 l 2157 6493 l
+ 2173 6487 l 2189 6482 l 2205 6478 l 2221 6475 l 2236 6472 l
+ 2251 6470 l 2265 6468 l 2280 6465 l 2295 6463 l 2310 6461 l
+ 2324 6459 l 2338 6457 l 2352 6456 l 2365 6454 l 2377 6453 l
+ 2389 6452 l 2400 6451 l 2410 6450 l
+ cp gs col13 1.00 shd ef gr gs col0 s gr
+% Polyline
+n 2452 4170 m 2451 4170 l 2448 4167 l 2439 4160 l 2424 4149 l 2405 4135 l
+ 2384 4118 l 2362 4102 l 2341 4086 l 2322 4071 l 2305 4059 l
+ 2290 4047 l 2277 4037 l 2265 4028 l 2254 4020 l 2242 4010 l
+ 2230 4000 l 2218 3991 l 2206 3981 l 2195 3972 l 2184 3963 l
+ 2174 3954 l 2164 3946 l 2155 3939 l 2147 3932 l 2140 3926 l
+ 2134 3920 l 2125 3912 l 2117 3905 l 2110 3897 l 2103 3891 l
+ 2098 3884 l 2093 3879 l 2090 3874 l 2088 3869 l 2087 3863 l
+ 2087 3858 l 2089 3852 l 2091 3846 l 2095 3840 l 2098 3834 l
+ 2102 3829 l 2107 3822 l 2112 3815 l 2117 3807 l 2122 3798 l
+ 2126 3790 l 2129 3784 l 2132 3776 l 2135 3768 l 2137 3760 l
+ 2140 3751 l 2142 3743 l 2144 3735 l 2146 3728 l 2147 3719 l
+ 2149 3710 l 2150 3700 l 2151 3689 l 2152 3679 l 2152 3669 l
+ 2152 3660 l 2152 3651 l 2152 3641 l 2151 3630 l 2151 3619 l
+ 2150 3609 l 2149 3598 l 2148 3589 l 2147 3579 l 2145 3570 l
+ 2143 3559 l 2140 3549 l 2138 3538 l 2135 3528 l 2132 3518 l
+ 2129 3508 l 2126 3499 l 2123 3489 l 2119 3478 l 2114 3466 l
+ 2109 3455 l 2104 3444 l 2098 3434 l 2091 3424 l 2086 3416 l
+ 2079 3408 l 2072 3400 l 2064 3392 l 2056 3384 l 2048 3376 l
+ 2040 3369 l 2032 3363 l 2025 3358 l 2018 3353 l 2010 3348 l
+ 2002 3344 l 1994 3340 l 1988 3337 l 1982 3333 l 1979 3329 l
+ 1978 3326 l 1978 3321 l 1981 3316 l 1985 3310 l 1990 3302 l
+ 1996 3294 l 2001 3286 l 2005 3277 l 2006 3269 l 2005 3262 l
+ 2002 3255 l 1995 3248 l 1985 3241 l 1974 3234 l 1961 3227 l
+ 1948 3221 l 1935 3216 l 1923 3211 l 1912 3207 l 1901 3202 l
+ 1891 3198 l 1880 3194 l 1870 3190 l 1860 3185 l 1851 3182 l
+ 1843 3178 l 1835 3174 l 1826 3170 l 1817 3165 l 1807 3160 l
+ 1797 3154 l 1787 3149 l 1777 3144 l 1767 3140 l 1759 3136 l
+ 1750 3132 l 1741 3127 l 1730 3123 l 1720 3118 l 1709 3113 l
+ 1698 3109 l 1687 3104 l 1677 3099 l 1667 3095 l 1655 3089 l
+ 1642 3083 l 1629 3077 l 1616 3072 l 1605 3067 l 1597 3065 l
+ 1590 3064 l 1586 3065 l 1585 3068 l 1585 3073 l 1588 3080 l
+ 1593 3089 l 1599 3098 l 1605 3108 l 1612 3118 l 1619 3127 l
+ 1625 3135 l 1632 3144 l 1639 3153 l 1646 3162 l 1652 3171 l
+ 1659 3180 l 1665 3189 l 1671 3198 l 1676 3207 l 1682 3217 l
+ 1688 3228 l 1694 3240 l 1700 3251 l 1706 3262 l 1711 3272 l
+ 1716 3282 l 1721 3291 l 1725 3300 l 1730 3309 l 1735 3319 l
+ 1740 3329 l 1744 3340 l 1748 3350 l 1752 3360 l 1756 3372 l
+ 1760 3384 l 1764 3397 l 1768 3410 l 1773 3422 l 1778 3433 l
+ 1782 3441 l 1787 3447 l 1791 3450 l 1795 3451 l 1800 3451 l
+ 1805 3451 l 1810 3449 l 1816 3446 l 1821 3442 l 1826 3438 l
+ 1831 3434 l 1836 3430 l 1845 3423 l 1854 3416 l 1863 3410 l
+ 1873 3405 l 1882 3402 l 1891 3402 l 1897 3403 l 1903 3406 l
+ 1910 3411 l 1917 3416 l 1924 3423 l 1931 3430 l 1938 3437 l
+ 1944 3445 l 1951 3452 l 1958 3461 l 1965 3470 l 1972 3479 l
+ 1979 3489 l 1986 3498 l 1991 3507 l 1996 3516 l 2000 3525 l
+ 2004 3534 l 2008 3544 l 2011 3554 l 2013 3564 l 2015 3574 l
+ 2017 3582 l 2018 3590 l 2020 3599 l 2021 3608 l 2021 3618 l
+ 2021 3627 l 2021 3636 l 2020 3644 l 2018 3653 l 2016 3662 l
+ 2013 3672 l 2009 3681 l 2005 3690 l 2000 3698 l 1994 3704 l
+ 1987 3711 l 1979 3718 l 1971 3724 l 1963 3730 l 1957 3735 l
+ 1950 3740 l 1944 3745 l 1937 3749 l 1931 3753 l 1924 3755 l
+ 1918 3756 l 1912 3754 l 1905 3751 l 1897 3747 l 1889 3742 l
+ 1881 3736 l 1874 3730 l 1868 3725 l 1861 3719 l 1853 3713 l
+ 1846 3707 l 1839 3701 l 1833 3696 l 1826 3691 l 1819 3686 l
+ 1812 3680 l 1804 3674 l 1796 3668 l 1789 3663 l 1784 3659 l
+ 1778 3654 l 1771 3649 l 1764 3643 l 1757 3637 l 1749 3632 l
+ 1742 3627 l 1735 3622 l 1728 3616 l 1721 3611 l 1713 3605 l
+ 1706 3598 l 1700 3592 l 1695 3585 l 1692 3578 l 1691 3571 l
+ 1691 3564 l 1693 3556 l 1697 3548 l 1702 3539 l 1707 3530 l
+ 1712 3522 l 1717 3515 l 1721 3509 l 1722 3507 l 1723 3505 l
+ 1724 3502 l 1725 3500 l 1726 3498 l 1726 3496 l 1726 3494 l
+ 1726 3493 l 1726 3491 l 1725 3489 l 1724 3487 l 1722 3486 l
+ 1720 3485 l 1718 3483 l 1716 3482 l 1713 3481 l 1709 3480 l
+ 1706 3479 l 1702 3478 l 1697 3477 l 1689 3476 l 1679 3475 l
+ 1668 3473 l 1654 3471 l 1639 3469 l 1623 3466 l 1605 3462 l
+ 1587 3457 l 1568 3452 l 1550 3446 l 1531 3439 l 1512 3431 l
+ 1495 3423 l 1477 3414 l 1459 3405 l 1440 3394 l 1421 3384 l
+ 1402 3373 l 1383 3362 l 1365 3352 l 1349 3343 l 1334 3336 l
+ 1321 3329 l 1310 3325 l 1301 3322 l 1294 3321 l 1288 3322 l
+ 1285 3325 l 1283 3330 l 1283 3337 l 1285 3346 l 1288 3356 l
+ 1292 3368 l 1297 3380 l 1304 3394 l 1310 3407 l 1317 3421 l
+ 1324 3435 l 1332 3448 l 1339 3462 l 1346 3477 l 1354 3492 l
+ 1362 3507 l 1370 3523 l 1378 3538 l 1386 3554 l 1393 3569 l
+ 1400 3583 l 1406 3597 l 1411 3609 l 1416 3620 l 1420 3631 l
+ 1426 3645 l 1430 3660 l 1434 3674 l 1438 3687 l 1441 3699 l
+ 1443 3709 l 1446 3718 l 1448 3725 l 1450 3732 l 1452 3737 l
+ 1455 3743 l 1458 3747 l 1461 3751 l 1464 3754 l 1467 3755 l
+ 1470 3756 l 1475 3756 l 1480 3754 l 1486 3750 l 1493 3746 l
+ 1500 3740 l 1507 3733 l 1513 3728 l 1519 3722 l 1526 3715 l
+ 1533 3709 l 1541 3703 l 1548 3699 l 1555 3695 l 1562 3694 l
+ 1568 3693 l 1575 3695 l 1582 3697 l 1590 3702 l 1598 3707 l
+ 1606 3713 l 1614 3719 l 1622 3726 l 1630 3733 l 1639 3740 l
+ 1649 3748 l 1660 3757 l 1670 3766 l 1680 3774 l 1689 3782 l
+ 1698 3789 l 1706 3795 l 1714 3802 l 1721 3810 l 1729 3817 l
+ 1736 3825 l 1743 3833 l 1748 3840 l 1754 3848 l 1758 3856 l
+ 1762 3865 l 1766 3874 l 1769 3885 l 1771 3895 l 1772 3904 l
+ 1772 3913 l 1770 3921 l 1767 3929 l 1762 3936 l 1756 3944 l
+ 1747 3952 l 1736 3959 l 1724 3966 l 1711 3973 l 1696 3980 l
+ 1687 3984 l 1677 3988 l 1666 3992 l 1654 3996 l 1641 4000 l
+ 1628 4004 l 1613 4008 l 1598 4011 l 1582 4014 l 1566 4016 l
+ 1551 4017 l 1535 4018 l 1519 4018 l 1503 4018 l 1487 4017 l
+ 1470 4015 l 1453 4012 l 1435 4008 l 1416 4004 l 1398 4000 l
+ 1380 3995 l 1362 3989 l 1346 3984 l 1331 3978 l 1318 3972 l
+ 1306 3967 l 1297 3962 l 1289 3957 l 1284 3953 l 1280 3950 l
+ 1277 3946 l 1274 3943 l 1272 3940 l 1271 3936 l 1270 3933 l
+ 1270 3930 l 1270 3927 l 1271 3923 l 1273 3920 l 1274 3917 l
+ 1277 3914 l 1279 3911 l 1282 3909 l 1285 3906 l 1288 3904 l
+ 1291 3901 l 1294 3899 l 1297 3897 l 1305 3892 l 1313 3886 l
+ 1321 3881 l 1329 3875 l 1336 3869 l 1343 3863 l 1348 3857 l
+ 1352 3852 l 1354 3848 l 1355 3843 l 1356 3839 l 1356 3834 l
+ 1356 3829 l 1354 3824 l 1351 3819 l 1348 3814 l 1343 3809 l
+ 1338 3805 l 1331 3801 l 1323 3797 l 1314 3794 l 1304 3790 l
+ 1292 3786 l 1278 3782 l 1263 3777 l 1247 3772 l 1229 3767 l
+ 1212 3761 l 1194 3755 l 1176 3748 l 1159 3740 l 1141 3732 l
+ 1126 3724 l 1111 3716 l 1095 3706 l 1079 3696 l 1062 3686 l
+ 1046 3675 l 1029 3664 l 1014 3654 l 998 3644 l 984 3635 l
+ 972 3627 l 960 3620 l 950 3614 l 941 3610 l 936 3608 l
+ 932 3607 l 928 3606 l 924 3605 l 921 3605 l 917 3605 l
+ 914 3605 l 912 3606 l 909 3607 l 907 3608 l 905 3610 l
+ 903 3612 l 902 3615 l 901 3618 l 900 3621 l 900 3624 l
+ 899 3628 l 899 3632 l 900 3636 l 900 3641 l 901 3645 l
+ 902 3650 l 903 3655 l 905 3660 l 906 3665 l 908 3671 l
+ 912 3681 l 916 3692 l 921 3705 l 928 3718 l 935 3733 l
+ 943 3748 l 951 3764 l 961 3781 l 970 3797 l 980 3814 l
+ 991 3830 l 1001 3846 l 1012 3862 l 1022 3878 l 1032 3891 l
+ 1042 3905 l 1053 3919 l 1064 3934 l 1076 3948 l 1089 3963 l
+ 1101 3978 l 1115 3993 l 1128 4008 l 1141 4022 l 1154 4035 l
+ 1167 4047 l 1180 4059 l 1192 4069 l 1204 4079 l 1216 4088 l
+ 1229 4098 l 1242 4107 l 1256 4115 l 1271 4123 l 1285 4131 l
+ 1301 4138 l 1316 4144 l 1331 4150 l 1347 4155 l 1362 4159 l
+ 1376 4163 l 1391 4167 l 1405 4170 l 1419 4173 l 1432 4175 l
+ 1447 4177 l 1462 4180 l 1477 4182 l 1493 4184 l 1510 4185 l
+ 1526 4186 l 1542 4187 l 1558 4188 l 1574 4188 l 1589 4188 l
+ 1603 4187 l 1616 4186 l 1629 4185 l 1643 4183 l 1658 4180 l
+ 1672 4177 l 1687 4173 l 1702 4168 l 1716 4163 l 1730 4158 l
+ 1744 4152 l 1757 4146 l 1769 4141 l 1781 4135 l 1792 4130 l
+ 1805 4124 l 1818 4117 l 1831 4110 l 1845 4103 l 1858 4096 l
+ 1871 4089 l 1882 4082 l 1893 4076 l 1902 4071 l 1909 4066 l
+ 1916 4062 l 1923 4057 l 1929 4053 l 1935 4050 l 1941 4047 l
+ 1947 4046 l 1952 4045 l 1958 4045 l 1964 4046 l 1971 4049 l
+ 1978 4052 l 1987 4057 l 1996 4064 l 2007 4071 l 2019 4080 l
+ 2031 4089 l 2043 4099 l 2055 4109 l 2067 4120 l 2079 4130 l
+ 2089 4139 l 2100 4148 l 2111 4158 l 2122 4168 l 2134 4178 l
+ 2146 4189 l 2158 4199 l 2170 4210 l 2181 4220 l 2192 4229 l
+ 2202 4238 l 2212 4246 l 2222 4254 l 2232 4262 l 2242 4271 l
+ 2254 4280 l 2267 4290 l 2281 4300 l 2296 4312 l 2309 4322 l
+ 2321 4331 l 2328 4336 l 2331 4339 l
+ 2332 4339 l gs col31 1.00 shd ef gr gs col0 s gr
+% Polyline
+n 2876 5202 m 2877 5203 l 2880 5207 l 2887 5217 l 2897 5231 l 2908 5246 l
+ 2919 5259 l 2928 5271 l 2936 5281 l 2943 5289 l 2949 5296 l
+ 2957 5304 l 2965 5312 l 2974 5320 l 2983 5327 l 2993 5334 l
+ 3002 5341 l 3011 5347 l 3020 5352 l 3029 5358 l 3039 5364 l
+ 3050 5370 l 3062 5377 l 3073 5383 l 3084 5389 l 3094 5393 l
+ 3104 5398 l 3113 5401 l 3122 5405 l 3132 5408 l 3141 5411 l
+ 3151 5413 l 3159 5415 l 3168 5417 l 3175 5419 l 3183 5421 l
+ 3191 5423 l 3199 5424 l 3208 5426 l 3217 5428 l 3226 5430 l
+ 3234 5431 l 3242 5432 l 3250 5433 l 3259 5434 l 3268 5435 l
+ 3277 5436 l 3286 5436 l 3294 5436 l 3302 5437 l 3309 5437 l
+ 3317 5437 l 3325 5436 l 3335 5436 l 3345 5435 l 3351 5434 l
+
+ 3352 5434 l gs col0 s gr
+% Polyline
+n 3161 5427 m 3162 5427 l 3166 5430 l 3176 5436 l 3192 5446 l 3211 5457 l
+ 3231 5469 l 3249 5480 l 3266 5489 l 3280 5497 l 3293 5504 l
+ 3303 5509 l 3314 5514 l 3325 5519 l 3336 5524 l 3347 5528 l
+ 3359 5532 l 3370 5535 l 3381 5538 l 3392 5540 l 3402 5543 l
+ 3412 5544 l 3422 5546 l 3432 5548 l 3442 5550 l 3454 5551 l
+ 3466 5553 l 3478 5554 l 3491 5556 l 3503 5556 l 3514 5557 l
+ 3525 5557 l 3536 5557 l 3546 5556 l 3556 5555 l 3566 5553 l
+ 3577 5551 l 3588 5549 l 3599 5546 l 3610 5543 l 3620 5540 l
+ 3630 5537 l 3640 5534 l 3650 5531 l 3661 5528 l 3672 5525 l
+ 3683 5521 l 3695 5518 l 3707 5514 l 3719 5511 l 3731 5507 l
+ 3741 5504 l 3752 5501 l 3762 5497 l 3773 5494 l 3784 5490 l
+ 3796 5487 l 3808 5483 l 3820 5479 l 3833 5476 l 3845 5473 l
+ 3856 5470 l 3868 5468 l 3879 5465 l 3892 5463 l 3905 5461 l
+ 3919 5459 l 3934 5457 l 3949 5455 l 3963 5453 l 3977 5452 l
+ 3990 5450 l 4002 5449 l 4015 5448 l 4027 5446 l 4041 5444 l
+ 4055 5442 l 4069 5440 l 4083 5438 l 4097 5435 l 4111 5431 l
+ 4125 5428 l 4138 5424 l 4149 5420 l 4160 5416 l 4173 5412 l
+ 4186 5407 l 4199 5401 l 4213 5396 l 4226 5390 l 4239 5384 l
+ 4252 5378 l 4265 5373 l 4276 5367 l 4288 5362 l 4301 5356 l
+ 4314 5350 l 4328 5344 l 4342 5338 l 4356 5332 l 4370 5326 l
+ 4383 5320 l 4395 5315 l 4407 5310 l 4418 5305 l 4429 5300 l
+ 4441 5296 l 4452 5291 l 4464 5286 l 4476 5280 l 4487 5275 l
+ 4498 5270 l 4508 5265 l 4517 5260 l 4525 5256 l 4535 5249 l
+ 4545 5242 l 4554 5235 l 4564 5227 l 4573 5218 l 4582 5209 l
+ 4590 5200 l 4597 5191 l 4603 5183 l 4609 5174 l 4616 5164 l
+ 4624 5152 l 4633 5137 l 4643 5122 l 4651 5108 l 4658 5098 l
+ 4661 5094 l
+ 4661 5093 l gs col0 s gr
+% Polyline
+n 2640 4897 m 2643 4902 l 2647 4907 l 2652 4912 l 2656 4917 l 2661 4921 l
+ 2666 4925 l 2672 4928 l 2678 4931 l 2685 4934 l 2692 4936 l
+ 2699 4938 l 2706 4939 l 2713 4940 l 2721 4941 l 2729 4942 l
+ 2736 4943 l 2743 4944 l 2750 4944 l 2756 4945 l 2763 4946 l
+ 2770 4947 l 2776 4947 l 2781 4948 l 2786 4947 l 2792 4947 l
+ 2798 4946 l 2805 4945 l 2813 4943 l 2821 4942 l 2828 4940 l
+ 2836 4939 l 2844 4937 l 2854 4935 l 2864 4933 l 2873 4930 l
+ 2881 4928 l 2889 4925 l 2899 4921 l 2908 4916 l 2918 4911 l
+ 2926 4905 l 2934 4899 l 2940 4894 l 2946 4889 l 2952 4883 l
+ 2958 4876 l 2964 4870 l 2969 4863 l 2974 4856 l 2980 4849 l
+ 2986 4841 l 2992 4832 l 2999 4822 l 3005 4813 l 3012 4805 l
+ 3018 4796 l 3024 4787 l 3031 4778 l 3038 4770 l 3044 4762 l
+ 3050 4756 l 3055 4751 l 3059 4745 l 3064 4740 l 3068 4736 l
+ 3071 4731 l 3074 4727 l 3076 4722 l 3077 4715 l 3077 4708 l
+ 3077 4701 l 3076 4695 l 3075 4689 l 3073 4682 l 3071 4674 l
+ 3069 4667 l 3066 4661 l 3064 4656 l 3062 4650 l 3059 4644 l
+ 3056 4639 l 3054 4633 l 3051 4628 l 3048 4623 l 3044 4617 l
+ 3041 4611 l 3037 4605 l 3033 4599 l 3029 4593 l 3028 4591 l
+ 3026 4589 l 3024 4587 l 3022 4585 l 3020 4583 l 3017 4582 l
+ 3013 4581 l 3008 4581 l 3003 4582 l 2997 4584 l 2991 4586 l
+ 2983 4589 l 2975 4593 l 2966 4598 l 2956 4605 l 2945 4612 l
+ 2934 4619 l 2923 4627 l 2910 4637 l 2896 4647 l 2881 4658 l
+ 2866 4670 l 2850 4683 l 2833 4697 l 2816 4710 l 2800 4724 l
+ 2783 4738 l 2767 4751 l 2752 4764 l 2738 4776 l 2725 4788 l
+ 2713 4799 l 2702 4809 l 2692 4818 l 2679 4830 l 2668 4841 l
+ 2659 4851 l 2651 4860 l 2646 4868 l 2641 4875 l 2639 4880 l
+ 2637 4885 l 2637 4889 l 2637 4892 l 2638 4895 l
+ cp gs col20 1.00 shd ef gr gs col0 s gr
+% Polyline
+n 2891 5190 m 2893 5191 l 2902 5194 l 2915 5198 l 2928 5203 l 2938 5206 l
+ 2947 5209 l 2955 5212 l 2964 5215 l 2974 5218 l 2983 5221 l
+ 2992 5224 l 3001 5226 l 3009 5228 l 3018 5230 l 3028 5231 l
+ 3037 5232 l 3046 5234 l 3054 5235 l 3062 5235 l 3070 5236 l
+ 3078 5237 l 3086 5237 l 3094 5238 l 3101 5238 l 3108 5239 l
+ 3115 5239 l 3123 5239 l 3131 5239 l 3139 5239 l 3145 5239 l
+ 3153 5239 l 3161 5239 l 3169 5239 l 3176 5239 l 3180 5238 l
+ 3182 5238 l 3183 5238 l 3184 5238 l 3185 5237 l 3186 5237 l
+ 3186 5236 l 3187 5236 l
+ 3187 5235 l gs col0 s gr
+% Polyline
+n 2468 6609 m 2462 6602 l 2456 6595 l 2448 6588 l 2440 6581 l 2432 6573 l
+ 2423 6566 l 2415 6559 l 2408 6553 l 2400 6547 l 2391 6540 l
+ 2382 6534 l 2373 6527 l 2363 6521 l 2353 6515 l 2344 6510 l
+ 2335 6506 l 2325 6501 l 2314 6497 l 2303 6494 l 2290 6490 l
+ 2278 6487 l 2265 6484 l 2253 6482 l 2242 6480 l 2232 6479 l
+ 2222 6478 l 2212 6476 l 2201 6476 l 2190 6475 l 2178 6474 l
+ 2167 6474 l 2155 6474 l 2144 6473 l 2134 6474 l 2122 6474 l
+ 2111 6474 l 2098 6475 l 2085 6475 l 2071 6476 l 2058 6477 l
+ 2044 6479 l 2031 6480 l 2018 6482 l 2006 6484 l 1996 6485 l
+ 1985 6487 l 1974 6489 l 1963 6491 l 1951 6493 l 1938 6496 l
+ 1926 6499 l 1913 6502 l 1900 6505 l 1887 6508 l 1875 6511 l
+ 1862 6515 l 1851 6517 l 1839 6521 l 1826 6524 l 1813 6527 l
+ 1799 6531 l 1785 6535 l 1770 6540 l 1755 6544 l 1740 6549 l
+ 1726 6553 l 1711 6558 l 1697 6563 l 1684 6567 l 1671 6572 l
+ 1656 6578 l 1640 6584 l 1624 6590 l 1608 6596 l 1592 6603 l
+ 1575 6611 l 1560 6618 l 1545 6625 l 1531 6631 l 1519 6637 l
+ 1508 6643 l 1498 6649 l 1484 6657 l 1472 6665 l 1461 6673 l
+ 1450 6682 l 1442 6690 l 1435 6697 l 1429 6704 l 1424 6710 l
+ 1418 6718 l 1413 6727 l 1409 6737 l 1406 6747 l 1404 6757 l
+ 1403 6767 l 1403 6775 l 1403 6783 l 1404 6793 l 1406 6803 l
+ 1408 6813 l 1410 6824 l 1412 6833 l 1415 6843 l 1418 6852 l
+ 1421 6861 l 1425 6871 l 1430 6881 l 1435 6891 l 1441 6901 l
+ 1446 6910 l 1453 6918 l 1459 6925 l 1467 6933 l 1476 6941 l
+ 1486 6949 l 1496 6956 l 1507 6963 l 1518 6969 l 1529 6975 l
+ 1538 6979 l 1548 6984 l 1558 6988 l 1570 6992 l 1582 6996 l
+ 1594 7000 l 1606 7004 l 1618 7007 l 1630 7010 l 1642 7013 l
+ 1654 7015 l 1667 7017 l 1680 7019 l 1695 7021 l 1710 7022 l
+ 1726 7024 l 1741 7025 l 1756 7026 l 1770 7027 l 1785 7028 l
+ 1796 7028 l 1809 7029 l 1822 7029 l 1835 7030 l 1849 7030 l
+ 1863 7030 l 1877 7031 l 1891 7031 l 1904 7031 l 1916 7032 l
+ 1928 7032 l 1939 7033 l 1952 7033 l 1965 7033 l 1979 7034 l
+ 1992 7034 l 2006 7035 l 2020 7035 l 2032 7036 l 2044 7036 l
+ 2056 7037 l 2067 7037 l 2077 7037 l 2088 7037 l 2099 7038 l
+ 2111 7038 l 2123 7038 l 2136 7038 l 2148 7038 l 2160 7038 l
+ 2172 7038 l 2183 7038 l 2191 7038 l 2200 7038 l 2209 7037 l
+ 2219 7036 l 2229 7035 l 2240 7033 l 2251 7029 l 2262 7025 l
+ 2273 7020 l 2284 7013 l 2295 7006 l 2306 6997 l 2317 6987 l
+ 2328 6976 l 2337 6964 l 2347 6951 l 2357 6937 l 2367 6922 l
+ 2377 6905 l 2388 6887 l 2398 6868 l 2408 6849 l 2418 6830 l
+ 2428 6811 l 2437 6793 l 2445 6775 l 2452 6759 l 2458 6743 l
+ 2464 6729 l 2469 6717 l 2474 6701 l 2478 6687 l 2481 6674 l
+ 2483 6663 l 2483 6653 l 2483 6643 l 2482 6635 l 2480 6628 l
+ 2478 6622 l 2475 6617 l 2472 6613 l
+ cp gs col7 1.00 shd ef gr gs col0 s gr
+% Polyline
+n 4102 4658 m 4100 4659 l 4092 4665 l 4080 4673 l 4068 4681 l 4059 4686 l
+ 4051 4690 l 4044 4693 l 4036 4696 l 4027 4698 l 4018 4700 l
+ 4009 4701 l 4001 4702 l 3994 4703 l 3986 4703 l 3978 4704 l
+ 3969 4704 l 3960 4705 l 3952 4705 l 3944 4705 l 3936 4706 l
+ 3927 4706 l 3917 4706 l 3907 4706 l 3897 4705 l 3888 4704 l
+ 3880 4703 l 3871 4701 l 3861 4699 l 3850 4696 l 3839 4693 l
+ 3829 4690 l 3819 4686 l 3811 4683 l 3802 4680 l 3793 4676 l
+ 3783 4672 l 3773 4668 l 3764 4663 l 3755 4658 l 3746 4654 l
+ 3737 4648 l 3728 4642 l 3719 4636 l 3709 4629 l 3699 4622 l
+ 3690 4615 l 3682 4609 l 3674 4603 l 3667 4597 l 3659 4591 l
+ 3651 4585 l 3643 4579 l 3635 4573 l 3627 4567 l 3619 4562 l
+ 3611 4557 l 3603 4552 l 3594 4547 l 3585 4541 l 3575 4536 l
+ 3564 4530 l 3554 4525 l 3544 4521 l 3535 4516 l 3525 4512 l
+ 3515 4507 l 3504 4503 l 3492 4499 l 3480 4494 l 3468 4490 l
+ 3456 4487 l 3445 4484 l 3435 4481 l 3425 4479 l 3414 4477 l
+ 3403 4475 l 3391 4473 l 3379 4471 l 3367 4469 l 3356 4468 l
+ 3345 4466 l 3335 4465 l 3325 4464 l 3314 4464 l 3303 4463 l
+ 3292 4462 l 3281 4462 l 3270 4462 l 3259 4462 l 3248 4462 l
+ 3238 4463 l 3229 4463 l 3217 4465 l 3204 4466 l 3192 4468 l
+ 3179 4471 l 3167 4474 l 3156 4476 l 3146 4479 l 3137 4482 l
+ 3129 4485 l 3122 4489 l 3114 4493 l 3106 4497 l 3099 4502 l
+ 3091 4506 l 3083 4511 l 3075 4517 l 3068 4521 l 3060 4526 l
+ 3050 4532 l 3039 4539 l 3025 4547 l 3010 4556 l 2996 4565 l
+ 2986 4571 l 2982 4574 l
+ 2981 4574 l gs col0 s gr
+% Polyline
+n 2940 2986 m 2939 2985 l 2932 2981 l 2920 2973 l 2905 2963 l 2891 2954 l
+ 2879 2947 l 2869 2941 l 2859 2937 l 2849 2933 l 2839 2930 l
+ 2827 2927 l 2816 2924 l 2804 2922 l 2792 2920 l 2781 2919 l
+ 2770 2918 l 2760 2918 l 2748 2917 l 2736 2918 l 2724 2918 l
+ 2712 2919 l 2700 2921 l 2689 2923 l 2679 2925 l 2669 2928 l
+ 2659 2932 l 2648 2936 l 2637 2941 l 2627 2946 l 2617 2952 l
+ 2608 2957 l 2601 2963 l 2593 2969 l 2586 2976 l 2579 2983 l
+ 2572 2991 l 2566 2999 l 2560 3008 l 2556 3016 l 2552 3024 l
+ 2548 3033 l 2545 3042 l 2542 3053 l 2540 3063 l 2538 3074 l
+ 2536 3085 l 2535 3095 l 2534 3105 l 2534 3114 l 2534 3124 l
+ 2534 3135 l 2534 3145 l 2536 3156 l 2537 3166 l 2540 3175 l
+ 2542 3184 l 2546 3193 l 2550 3202 l 2555 3212 l 2560 3222 l
+ 2567 3231 l 2573 3240 l 2579 3248 l 2586 3255 l 2592 3262 l
+ 2599 3268 l 2607 3275 l 2616 3281 l 2624 3288 l 2632 3293 l
+ 2640 3298 l 2648 3303 l 2656 3307 l 2664 3311 l 2673 3315 l
+ 2683 3319 l 2693 3323 l 2702 3326 l 2712 3329 l 2721 3331 l
+ 2730 3333 l 2740 3335 l 2750 3336 l 2762 3338 l 2773 3339 l
+ 2783 3340 l 2794 3340 l 2803 3341 l 2812 3341 l 2822 3341 l
+ 2832 3342 l 2842 3342 l 2852 3341 l 2862 3341 l 2871 3341 l
+ 2880 3340 l 2889 3339 l 2898 3339 l 2907 3337 l 2917 3336 l
+ 2926 3335 l 2935 3334 l 2944 3332 l 2951 3331 l 2961 3329 l
+ 2970 3328 l 2980 3326 l 2989 3324 l 2997 3323 l 3005 3323 l
+ 3012 3322 l 3019 3322 l 3026 3323 l 3033 3324 l 3040 3326 l
+ 3047 3329 l 3053 3332 l 3061 3336 l 3070 3340 l 3079 3344 l
+ 3088 3348 l 3097 3350 l 3107 3352 l 3117 3353 l 3129 3352 l
+ 3140 3352 l 3150 3351 l 3159 3349 l 3167 3348 l 3175 3346 l
+ 3182 3343 l 3188 3340 l 3193 3336 l 3197 3331 l 3200 3325 l
+ 3203 3317 l 3205 3308 l 3206 3298 l 3206 3287 l 3206 3278 l
+ 3205 3268 l 3204 3257 l 3201 3246 l 3198 3235 l 3195 3225 l
+ 3191 3217 l 3187 3210 l 3181 3203 l 3173 3195 l 3164 3187 l
+ 3158 3182 l
+ 3157 3181 l gs col0 s gr
+% Polyline
+n 3309 2031 m 3318 2017 l 3328 2004 l 3338 1992 l 3349 1979 l 3360 1967 l
+ 3371 1955 l 3382 1943 l 3394 1932 l 3405 1922 l 3417 1913 l
+ 3428 1904 l 3440 1895 l 3452 1886 l 3466 1878 l 3480 1869 l
+ 3495 1861 l 3511 1853 l 3528 1845 l 3544 1839 l 3561 1834 l
+ 3577 1830 l 3592 1828 l 3607 1828 l 3621 1829 l 3632 1831 l
+ 3644 1835 l 3656 1839 l 3668 1845 l 3679 1853 l 3691 1861 l
+ 3702 1871 l 3713 1882 l 3723 1893 l 3733 1904 l 3741 1916 l
+ 3749 1928 l 3756 1940 l 3762 1952 l 3767 1965 l 3772 1978 l
+ 3777 1991 l 3781 2006 l 3785 2021 l 3788 2037 l 3791 2054 l
+ 3793 2071 l 3795 2088 l 3797 2106 l 3798 2123 l 3798 2140 l
+ 3799 2157 l 3799 2174 l 3799 2189 l 3799 2205 l 3798 2222 l
+ 3798 2239 l 3797 2258 l 3796 2277 l 3795 2296 l 3793 2316 l
+ 3792 2336 l 3790 2356 l 3787 2376 l 3785 2395 l 3783 2414 l
+ 3780 2433 l 3777 2451 l 3774 2469 l 3770 2486 l 3767 2504 l
+ 3763 2522 l 3758 2541 l 3753 2560 l 3748 2580 l 3743 2599 l
+ 3737 2619 l 3731 2638 l 3724 2657 l 3718 2676 l 3711 2693 l
+ 3705 2710 l 3698 2726 l 3692 2741 l 3685 2756 l 3677 2773 l
+ 3669 2789 l 3661 2805 l 3651 2821 l 3641 2837 l 3631 2853 l
+ 3620 2869 l 3609 2884 l 3597 2899 l 3586 2912 l 3574 2925 l
+ 3562 2936 l 3551 2947 l 3539 2957 l 3527 2967 l 3514 2976 l
+ 3500 2985 l 3486 2993 l 3471 3001 l 3455 3009 l 3439 3016 l
+ 3422 3022 l 3405 3027 l 3389 3031 l 3373 3034 l 3358 3036 l
+ 3343 3037 l 3328 3038 l 3313 3037 l 3298 3036 l 3283 3033 l
+ 3267 3030 l 3251 3025 l 3235 3019 l 3219 3013 l 3204 3005 l
+ 3189 2997 l 3175 2988 l 3162 2979 l 3150 2969 l 3139 2958 l
+ 3129 2948 l 3120 2936 l 3111 2924 l 3103 2911 l 3095 2896 l
+ 3087 2881 l 3080 2865 l 3074 2849 l 3068 2832 l 3063 2816 l
+ 3059 2799 l 3055 2784 l 3052 2768 l 3049 2754 l 3047 2740 l
+ 3045 2726 l 3044 2712 l 3043 2697 l 3042 2683 l 3042 2667 l
+ 3042 2652 l 3043 2636 l 3044 2620 l 3046 2604 l 3048 2588 l
+ 3051 2572 l 3055 2557 l 3058 2542 l 3062 2526 l 3066 2512 l
+ 3071 2498 l 3076 2483 l 3081 2467 l 3088 2451 l 3094 2433 l
+ 3101 2416 l 3109 2398 l 3116 2379 l 3124 2361 l 3132 2344 l
+ 3140 2326 l 3148 2309 l 3156 2293 l 3164 2277 l 3172 2262 l
+ 3180 2247 l 3188 2231 l 3196 2216 l 3204 2200 l 3213 2184 l
+ 3222 2168 l 3232 2152 l 3241 2136 l 3250 2120 l 3260 2105 l
+ 3269 2091 l 3277 2077 l 3286 2065 l 3294 2053 l 3301 2041 l
+
+ cp gs col7 1.00 shd ef gr gs col0 s gr
+% Polyline
+45.000 slw
+n 2498 3459 m 2499 3459 l 2505 3459 l 2517 3459 l 2532 3460 l 2545 3461 l
+ 2555 3461 l 2563 3462 l 2571 3464 l 2579 3467 l 2587 3471 l
+ 2595 3476 l 2603 3481 l 2610 3488 l 2617 3495 l 2623 3501 l
+ 2629 3507 l 2636 3514 l 2643 3522 l 2651 3530 l 2658 3538 l
+ 2665 3546 l 2672 3553 l 2679 3560 l 2686 3568 l 2693 3576 l
+ 2701 3584 l 2708 3592 l 2716 3599 l 2723 3606 l 2730 3613 l
+ 2737 3620 l 2744 3627 l 2752 3634 l 2761 3642 l 2769 3649 l
+ 2777 3657 l 2785 3664 l 2792 3672 l 2799 3679 l 2807 3687 l
+ 2815 3695 l 2824 3704 l 2833 3713 l 2841 3722 l 2850 3730 l
+ 2859 3737 l 2866 3743 l 2874 3749 l 2883 3756 l 2892 3762 l
+ 2902 3769 l 2911 3775 l 2921 3781 l 2931 3787 l 2940 3793 l
+ 2950 3798 l 2959 3803 l 2969 3809 l 2979 3814 l 2990 3820 l
+ 3001 3826 l 3012 3831 l 3024 3836 l 3035 3841 l 3045 3845 l
+ 3056 3849 l 3066 3853 l 3077 3856 l 3089 3859 l 3101 3862 l
+ 3114 3865 l 3127 3868 l 3141 3870 l 3154 3872 l 3166 3874 l
+ 3179 3876 l 3189 3877 l 3201 3878 l 3212 3879 l 3225 3879 l
+ 3238 3880 l 3251 3880 l 3264 3881 l 3277 3881 l 3289 3881 l
+ 3301 3881 l 3312 3880 l 3323 3880 l 3336 3879 l 3349 3878 l
+ 3362 3876 l 3376 3875 l 3390 3872 l 3404 3870 l 3417 3867 l
+ 3430 3864 l 3442 3860 l 3454 3857 l 3466 3852 l 3478 3848 l
+ 3491 3843 l 3504 3837 l 3518 3831 l 3531 3825 l 3544 3818 l
+ 3556 3813 l 3568 3807 l 3579 3802 l 3590 3796 l 3601 3791 l
+ 3612 3785 l 3624 3780 l 3636 3774 l 3647 3768 l 3659 3762 l
+ 3670 3756 l 3681 3750 l 3692 3744 l 3703 3738 l 3715 3731 l
+ 3727 3724 l 3739 3717 l 3751 3709 l 3764 3701 l 3775 3693 l
+ 3785 3686 l 3795 3680 l 3803 3673 l 3812 3666 l 3821 3658 l
+ 3829 3650 l 3837 3643 l 3844 3637 l 3852 3631 l 3859 3626 l
+ 3866 3622 l 3873 3619 l 3881 3617 l 3891 3614 l 3901 3613 l
+ 3910 3612 l 3920 3611 l 3928 3610 l 3936 3610 l 3945 3610 l
+ 3954 3609 l 3964 3609 l 3975 3609 l 3982 3609 l
+ 3983 3609 l gs col0 s gr
+% Polyline
+30.000 slw
+n 2870 2736 m 2876 2727 l 2882 2719 l 2888 2710 l 2895 2701 l 2901 2690 l
+ 2907 2679 l 2913 2667 l 2919 2654 l 2925 2640 l 2931 2625 l
+ 2935 2612 l 2940 2599 l 2945 2585 l 2950 2569 l 2956 2552 l
+ 2962 2534 l 2967 2515 l 2973 2496 l 2979 2477 l 2985 2459 l
+ 2991 2440 l 2996 2423 l 3001 2406 l 3006 2390 l 3011 2374 l
+ 3016 2359 l 3021 2343 l 3026 2327 l 3031 2311 l 3036 2295 l
+ 3041 2279 l 3046 2264 l 3051 2249 l 3056 2235 l 3061 2222 l
+ 3065 2210 l 3069 2199 l 3073 2188 l 3078 2175 l 3083 2163 l
+ 3088 2151 l 3092 2139 l 3097 2127 l 3102 2114 l 3107 2102 l
+ 3112 2091 l 3117 2080 l 3121 2070 l 3125 2060 l 3129 2051 l
+ 3133 2039 l 3138 2028 l 3142 2016 l 3147 2003 l 3152 1991 l
+ 3156 1979 l 3160 1968 l 3164 1957 l 3167 1948 l 3170 1939 l
+ 3173 1929 l 3176 1919 l 3179 1909 l 3180 1899 l 3181 1889 l
+ 3180 1879 l 3179 1869 l 3176 1859 l 3173 1851 l 3170 1844 l
+ 3166 1836 l 3161 1827 l 3155 1819 l 3149 1811 l 3141 1803 l
+ 3133 1796 l 3125 1790 l 3116 1785 l 3107 1782 l 3098 1780 l
+ 3088 1778 l 3077 1778 l 3066 1780 l 3053 1782 l 3040 1785 l
+ 3027 1789 l 3014 1794 l 3001 1800 l 2989 1805 l 2978 1811 l
+ 2967 1816 l 2958 1822 l 2947 1829 l 2936 1836 l 2926 1843 l
+ 2916 1851 l 2906 1860 l 2896 1870 l 2886 1880 l 2876 1891 l
+ 2866 1902 l 2856 1915 l 2848 1924 l 2840 1934 l 2831 1946 l
+ 2822 1958 l 2812 1971 l 2801 1986 l 2790 2000 l 2780 2016 l
+ 2769 2031 l 2758 2047 l 2748 2062 l 2738 2077 l 2729 2092 l
+ 2720 2107 l 2711 2122 l 2702 2137 l 2693 2153 l 2684 2169 l
+ 2675 2185 l 2666 2202 l 2658 2219 l 2650 2235 l 2642 2251 l
+ 2635 2265 l 2628 2279 l 2622 2292 l 2616 2304 l 2611 2315 l
+ 2605 2327 l 2600 2339 l 2595 2350 l 2591 2361 l 2586 2373 l
+ 2582 2385 l 2578 2396 l 2575 2408 l 2572 2421 l 2569 2433 l
+ 2566 2446 l 2564 2460 l 2562 2472 l 2560 2486 l 2558 2500 l
+ 2557 2516 l 2555 2533 l 2554 2551 l 2553 2568 l 2552 2586 l
+ 2551 2604 l 2551 2621 l 2552 2637 l 2552 2652 l 2553 2666 l
+ 2555 2680 l 2558 2697 l 2562 2713 l 2567 2728 l 2573 2742 l
+ 2579 2756 l 2586 2768 l 2593 2779 l 2600 2788 l 2607 2796 l
+ 2614 2803 l 2622 2810 l 2630 2817 l 2639 2824 l 2648 2829 l
+ 2658 2834 l 2667 2838 l 2677 2841 l 2686 2843 l 2696 2845 l
+ 2708 2845 l 2720 2845 l 2733 2844 l 2747 2841 l 2760 2838 l
+ 2772 2832 l 2783 2826 l 2792 2820 l 2802 2813 l 2811 2804 l
+ 2821 2795 l 2830 2785 l 2839 2774 l 2848 2764 l 2856 2754 l
+ 2863 2744 l
+ cp gs col7 1.00 shd ef gr gs col0 s gr
+% Polyline
+n 3489 1649 m 3490 1649 l 3494 1646 l 3504 1640 l 3520 1632 l 3539 1622 l
+ 3559 1611 l 3578 1601 l 3596 1593 l 3612 1586 l 3626 1581 l
+ 3639 1577 l 3652 1573 l 3665 1571 l 3678 1569 l 3692 1568 l
+ 3706 1568 l 3721 1568 l 3736 1569 l 3751 1571 l 3766 1573 l
+ 3780 1576 l 3793 1580 l 3805 1584 l 3817 1588 l 3829 1593 l
+ 3840 1599 l 3852 1605 l 3863 1612 l 3875 1621 l 3886 1630 l
+ 3897 1640 l 3907 1650 l 3917 1661 l 3925 1672 l 3933 1684 l
+ 3940 1696 l 3946 1707 l 3952 1719 l 3957 1733 l 3962 1748 l
+ 3968 1765 l 3974 1785 l 3980 1807 l 3986 1830 l 3992 1852 l
+ 3998 1873 l 4002 1888 l 4004 1897 l 4005 1901 l
+ 4005 1902 l gs col0 s gr
+% Polyline
+n 3278 1680 m 3278 1679 l 3277 1674 l 3274 1664 l 3270 1650 l 3265 1634 l
+ 3260 1620 l 3256 1607 l 3251 1598 l 3246 1589 l 3241 1583 l
+ 3234 1576 l 3227 1571 l 3219 1566 l 3209 1561 l 3199 1557 l
+ 3188 1553 l 3177 1550 l 3165 1548 l 3154 1546 l 3143 1545 l
+ 3132 1544 l 3120 1543 l 3107 1543 l 3093 1544 l 3079 1545 l
+ 3064 1547 l 3050 1550 l 3037 1554 l 3024 1558 l 3011 1563 l
+ 3001 1569 l 2991 1575 l 2980 1582 l 2969 1590 l 2957 1599 l
+ 2945 1609 l 2933 1620 l 2920 1631 l 2908 1643 l 2896 1654 l
+ 2885 1666 l 2873 1678 l 2864 1688 l 2854 1697 l 2844 1708 l
+ 2834 1719 l 2823 1730 l 2812 1742 l 2801 1755 l 2789 1768 l
+ 2778 1782 l 2766 1795 l 2755 1809 l 2744 1823 l 2734 1836 l
+ 2724 1849 l 2714 1862 l 2705 1876 l 2696 1889 l 2687 1903 l
+ 2678 1917 l 2669 1932 l 2660 1948 l 2651 1964 l 2642 1980 l
+ 2633 1997 l 2624 2014 l 2616 2030 l 2608 2046 l 2601 2062 l
+ 2594 2077 l 2588 2092 l 2582 2106 l 2576 2119 l 2570 2134 l
+ 2564 2150 l 2558 2165 l 2553 2181 l 2547 2197 l 2541 2213 l
+ 2536 2229 l 2531 2244 l 2526 2260 l 2521 2274 l 2517 2288 l
+ 2512 2301 l 2508 2313 l 2504 2325 l 2499 2338 l 2495 2352 l
+ 2489 2366 l 2484 2380 l 2479 2394 l 2473 2409 l 2467 2423 l
+ 2462 2437 l 2456 2451 l 2451 2464 l 2446 2477 l 2441 2490 l
+ 2437 2503 l 2432 2517 l 2426 2532 l 2420 2549 l 2413 2568 l
+ 2406 2590 l 2398 2613 l 2391 2635 l 2385 2652 l 2381 2664 l
+ 2379 2669 l
+ 2379 2670 l gs col0 s gr
+% Polyline
+n 4036 5613 m 4048 5621 l 4060 5629 l 4071 5637 l 4083 5644 l 4095 5652 l
+ 4106 5659 l 4117 5666 l 4128 5673 l 4138 5679 l 4147 5685 l
+ 4157 5691 l 4165 5696 l 4176 5703 l 4187 5710 l 4198 5717 l
+ 4210 5724 l 4221 5732 l 4233 5739 l 4245 5747 l 4255 5754 l
+ 4265 5760 l 4275 5767 l 4284 5773 l 4294 5779 l 4304 5785 l
+ 4314 5792 l 4323 5798 l 4333 5805 l 4342 5810 l 4350 5816 l
+ 4357 5820 l 4363 5824 l 4373 5831 l 4382 5836 l 4391 5841 l
+ 4399 5845 l 4406 5848 l 4412 5850 l 4419 5851 l 4426 5851 l
+ 4433 5851 l 4440 5850 l 4446 5848 l 4451 5846 l 4457 5844 l
+ 4462 5840 l 4467 5837 l 4471 5834 l 4475 5830 l 4479 5826 l
+ 4482 5821 l 4486 5816 l 4490 5811 l 4493 5806 l 4497 5801 l
+ 4501 5796 l 4506 5790 l 4509 5785 l 4512 5780 l 4516 5774 l
+ 4519 5767 l 4521 5760 l 4523 5753 l 4524 5747 l 4524 5740 l
+ 4524 5734 l 4523 5727 l 4522 5719 l 4521 5713 l 4520 5707 l
+ 4518 5702 l 4515 5697 l 4512 5691 l 4508 5686 l 4504 5682 l
+ 4499 5677 l 4494 5673 l 4489 5668 l 4482 5663 l 4475 5658 l
+ 4468 5653 l 4461 5648 l 4454 5643 l 4446 5638 l 4437 5632 l
+ 4427 5626 l 4417 5620 l 4408 5614 l 4400 5609 l 4391 5604 l
+ 4382 5598 l 4371 5591 l 4361 5584 l 4351 5578 l 4341 5571 l
+ 4332 5565 l 4322 5559 l 4313 5553 l 4303 5546 l 4292 5540 l
+ 4283 5534 l 4274 5528 l 4266 5523 l 4258 5519 l 4252 5515 l
+ 4245 5511 l 4238 5507 l 4231 5503 l 4224 5499 l 4217 5495 l
+ 4210 5491 l 4203 5486 l 4195 5480 l 4186 5474 l 4177 5468 l
+ 4167 5460 l 4158 5453 l 4149 5447 l 4142 5442 l 4136 5437 l
+ 4131 5434 l 4127 5431 l 4124 5429 l 4120 5428 l 4116 5428 l
+ 4112 5428 l 4106 5428 l 4100 5429 l 4093 5430 l 4085 5431 l
+ 4076 5433 l 4066 5434 l 4054 5436 l 4042 5438 l 4029 5440 l
+ 4017 5441 l 4005 5443 l 3993 5445 l 3981 5447 l 3969 5449 l
+ 3957 5450 l 3944 5452 l 3932 5455 l 3920 5457 l 3910 5459 l
+ 3900 5460 l 3892 5462 l 3885 5464 l 3882 5465 l 3880 5465 l
+ 3878 5466 l 3876 5467 l 3874 5468 l 3872 5468 l 3871 5469 l
+ 3869 5470 l 3868 5471 l 3867 5472 l 3867 5474 l 3866 5475 l
+ 3866 5476 l 3866 5478 l 3866 5479 l 3867 5481 l 3868 5483 l
+ 3869 5485 l 3870 5487 l 3872 5489 l 3874 5491 l 3876 5493 l
+ 3878 5496 l 3881 5498 l 3884 5501 l 3887 5504 l 3894 5510 l
+ 3904 5517 l 3914 5526 l 3926 5535 l 3939 5545 l 3954 5555 l
+ 3968 5566 l 3983 5576 l 3997 5586 l 4011 5596 l 4024 5605 l
+
+ cp gs col31 1.00 shd ef gr gs col0 s gr
+7.500 slw
+% Rotated Ellipse
+gs
+3291 2663 tr
+-345.998 rot
+n 0 0 179 279 0 360 DrawEllipse 345.998 rot
+gs 0.00 setgray ef gr gs col0 s gr
+gr
+
+% Polyline
+30.000 slw
+n 2303 4762 m 2309 4770 l 2316 4777 l 2323 4784 l 2330 4792 l 2337 4799 l
+ 2344 4805 l 2350 4811 l 2356 4816 l 2364 4823 l 2372 4830 l
+ 2381 4837 l 2390 4843 l 2399 4848 l 2408 4852 l 2415 4854 l
+ 2423 4857 l 2432 4859 l 2441 4861 l 2451 4863 l 2461 4864 l
+ 2471 4866 l 2480 4867 l 2489 4867 l 2500 4868 l 2510 4869 l
+ 2522 4869 l 2533 4869 l 2543 4869 l 2554 4869 l 2563 4868 l
+ 2572 4867 l 2582 4866 l 2592 4865 l 2602 4863 l 2613 4861 l
+ 2623 4859 l 2633 4857 l 2642 4855 l 2651 4853 l 2661 4850 l
+ 2672 4848 l 2682 4845 l 2693 4842 l 2703 4839 l 2712 4836 l
+ 2720 4833 l 2728 4831 l 2736 4827 l 2744 4824 l 2751 4820 l
+ 2759 4816 l 2766 4812 l 2773 4807 l 2779 4802 l 2785 4797 l
+ 2792 4791 l 2799 4784 l 2807 4777 l 2815 4769 l 2823 4760 l
+ 2830 4752 l 2838 4744 l 2844 4737 l 2851 4730 l 2858 4723 l
+ 2865 4715 l 2873 4706 l 2880 4698 l 2888 4690 l 2895 4682 l
+ 2901 4674 l 2908 4667 l 2915 4658 l 2923 4649 l 2931 4640 l
+ 2939 4630 l 2947 4621 l 2953 4612 l 2960 4604 l 2965 4597 l
+ 2970 4589 l 2975 4582 l 2979 4574 l 2984 4566 l 2987 4558 l
+ 2990 4551 l 2993 4544 l 2994 4537 l 2996 4530 l 2996 4522 l
+ 2997 4514 l 2997 4506 l 2997 4497 l 2996 4488 l 2996 4480 l
+ 2995 4472 l 2994 4464 l 2993 4455 l 2991 4446 l 2989 4437 l
+ 2987 4427 l 2984 4418 l 2981 4410 l 2977 4403 l 2972 4395 l
+ 2967 4388 l 2961 4381 l 2954 4373 l 2947 4367 l 2939 4360 l
+ 2932 4354 l 2926 4349 l 2919 4344 l 2912 4340 l 2904 4335 l
+ 2896 4330 l 2888 4326 l 2881 4322 l 2873 4318 l 2866 4315 l
+ 2859 4311 l 2851 4308 l 2843 4305 l 2834 4302 l 2825 4300 l
+ 2817 4297 l 2809 4295 l 2801 4294 l 2793 4293 l 2785 4292 l
+ 2776 4291 l 2767 4291 l 2758 4291 l 2750 4291 l 2742 4292 l
+ 2734 4293 l 2724 4294 l 2714 4296 l 2704 4298 l 2693 4302 l
+ 2684 4305 l 2676 4309 l 2672 4312 l 2667 4315 l 2661 4320 l
+ 2654 4326 l 2645 4333 l 2635 4342 l 2623 4353 l 2609 4366 l
+ 2593 4380 l 2575 4397 l 2564 4407 l 2552 4418 l 2538 4430 l
+ 2524 4443 l 2509 4457 l 2493 4472 l 2477 4487 l 2460 4503 l
+ 2443 4519 l 2426 4535 l 2410 4552 l 2394 4567 l 2380 4582 l
+ 2366 4597 l 2353 4610 l 2342 4623 l 2331 4635 l 2322 4646 l
+ 2314 4658 l 2306 4668 l 2300 4679 l 2295 4688 l 2291 4698 l
+ 2288 4706 l 2287 4714 l 2286 4722 l 2286 4729 l 2287 4735 l
+ 2289 4741 l 2291 4746 l 2294 4750 l 2297 4755 l 2300 4759 l
+
+ cp gs col20 1.00 shd ef gr gs col0 s gr
+7.500 slw
+% Rotated Ellipse
+gs
+2748 2543 tr
+-345.998 rot
+n 0 0 130 238 0 360 DrawEllipse 345.998 rot
+gs 0.00 setgray ef gr gs col0 s gr
+gr
+
+% Rotated Ellipse
+gs
+2738 2495 tr
+-350.003 rot
+n 0 0 55 105 0 360 DrawEllipse 350.003 rot
+gs col7 1.00 shd ef gr gs col0 s gr
+gr
+
+% Polyline
+30.000 slw
+n 2288 6848 m 2292 6837 l 2298 6827 l 2305 6815 l 2313 6804 l 2322 6793 l
+ 2332 6783 l 2342 6773 l 2351 6764 l 2360 6757 l 2369 6750 l
+ 2378 6743 l 2386 6738 l 2395 6732 l 2403 6726 l 2413 6721 l
+ 2422 6716 l 2430 6711 l 2439 6707 l 2448 6703 l 2456 6699 l
+ 2465 6694 l 2474 6689 l 2484 6684 l 2495 6679 l 2506 6674 l
+ 2518 6668 l 2529 6663 l 2540 6658 l 2550 6653 l 2560 6649 l
+ 2570 6645 l 2580 6641 l 2591 6637 l 2602 6633 l 2614 6629 l
+ 2626 6626 l 2637 6622 l 2648 6619 l 2659 6616 l 2670 6614 l
+ 2681 6611 l 2692 6608 l 2705 6606 l 2718 6603 l 2731 6601 l
+ 2744 6598 l 2757 6596 l 2770 6594 l 2782 6592 l 2794 6591 l
+ 2805 6589 l 2817 6588 l 2829 6586 l 2842 6585 l 2855 6584 l
+ 2868 6583 l 2880 6583 l 2892 6582 l 2903 6582 l 2914 6582 l
+ 2925 6581 l 2936 6582 l 2948 6582 l 2960 6582 l 2972 6583 l
+ 2985 6584 l 2997 6585 l 3008 6586 l 3020 6587 l 3031 6589 l
+ 3041 6590 l 3053 6592 l 3065 6594 l 3077 6597 l 3090 6599 l
+ 3102 6602 l 3114 6605 l 3126 6607 l 3136 6610 l 3146 6613 l
+ 3158 6617 l 3170 6620 l 3182 6625 l 3195 6629 l 3207 6634 l
+ 3218 6639 l 3228 6644 l 3238 6650 l 3248 6655 l 3258 6661 l
+ 3268 6668 l 3279 6676 l 3290 6684 l 3300 6692 l 3309 6700 l
+ 3318 6709 l 3325 6715 l 3332 6722 l 3339 6730 l 3346 6738 l
+ 3353 6746 l 3360 6755 l 3367 6763 l 3373 6772 l 3378 6780 l
+ 3383 6788 l 3389 6797 l 3394 6808 l 3399 6820 l 3404 6832 l
+ 3409 6844 l 3413 6856 l 3416 6868 l 3420 6879 l 3422 6888 l
+ 3424 6898 l 3426 6908 l 3428 6919 l 3430 6930 l 3432 6940 l
+ 3433 6951 l 3435 6960 l 3436 6970 l 3437 6978 l 3437 6983 l
+ 3437 6988 l 3437 6993 l 3436 6998 l 3435 7004 l 3433 7009 l
+ 3431 7014 l 3427 7020 l 3422 7025 l 3417 7030 l 3410 7036 l
+ 3402 7041 l 3393 7046 l 3382 7050 l 3371 7055 l 3358 7060 l
+ 3346 7064 l 3333 7068 l 3319 7072 l 3303 7076 l 3287 7080 l
+ 3268 7084 l 3248 7088 l 3227 7091 l 3205 7095 l 3182 7098 l
+ 3157 7101 l 3133 7104 l 3107 7106 l 3081 7108 l 3056 7109 l
+ 3030 7109 l 3004 7110 l 2978 7109 l 2952 7108 l 2926 7107 l
+ 2902 7105 l 2877 7102 l 2852 7099 l 2826 7096 l 2800 7092 l
+ 2773 7088 l 2746 7083 l 2718 7077 l 2690 7071 l 2662 7065 l
+ 2634 7059 l 2607 7052 l 2581 7045 l 2556 7038 l 2531 7031 l
+ 2508 7024 l 2486 7017 l 2466 7010 l 2447 7003 l 2429 6996 l
+ 2413 6990 l 2398 6983 l 2381 6976 l 2366 6968 l 2352 6960 l
+ 2339 6952 l 2328 6944 l 2318 6936 l 2309 6928 l 2302 6920 l
+ 2296 6912 l 2291 6904 l 2288 6896 l 2285 6888 l 2284 6881 l
+ 2283 6874 l 2283 6867 l 2284 6861 l 2286 6854 l
+ cp gs col7 1.00 shd ef gr gs col0 s gr
+% Polyline
+n 2232 4239 m 2224 4242 l 2216 4247 l 2207 4251 l 2198 4256 l 2190 4261 l
+ 2183 4267 l 2176 4272 l 2169 4278 l 2162 4286 l 2154 4294 l
+ 2147 4303 l 2140 4313 l 2135 4320 l 2130 4329 l 2125 4338 l
+ 2119 4349 l 2114 4359 l 2110 4369 l 2106 4379 l 2104 4387 l
+ 2101 4396 l 2099 4405 l 2098 4414 l 2097 4423 l 2096 4432 l
+ 2096 4441 l 2096 4449 l 2095 4458 l 2095 4466 l 2095 4475 l
+ 2095 4484 l 2095 4495 l 2095 4505 l 2096 4514 l 2096 4523 l
+ 2098 4532 l 2099 4540 l 2102 4548 l 2105 4557 l 2109 4566 l
+ 2114 4575 l 2119 4583 l 2125 4591 l 2131 4599 l 2138 4606 l
+ 2147 4614 l 2156 4622 l 2166 4630 l 2176 4638 l 2186 4645 l
+ 2196 4651 l 2204 4656 l 2213 4661 l 2222 4665 l 2231 4668 l
+ 2240 4671 l 2250 4674 l 2260 4676 l 2269 4677 l 2279 4679 l
+ 2289 4680 l 2300 4681 l 2312 4683 l 2325 4684 l 2338 4685 l
+ 2351 4686 l 2362 4686 l 2373 4687 l 2384 4688 l 2395 4688 l
+ 2407 4688 l 2418 4688 l 2430 4688 l 2442 4686 l 2452 4685 l
+ 2463 4683 l 2472 4680 l 2481 4677 l 2490 4674 l 2500 4670 l
+ 2510 4665 l 2521 4660 l 2530 4655 l 2540 4650 l 2548 4644 l
+ 2557 4639 l 2567 4632 l 2577 4624 l 2587 4616 l 2597 4607 l
+ 2606 4598 l 2614 4589 l 2620 4581 l 2626 4573 l 2631 4565 l
+ 2635 4558 l 2639 4550 l 2642 4541 l 2645 4533 l 2647 4526 l
+ 2648 4519 l 2650 4512 l 2651 4504 l 2653 4494 l 2654 4484 l
+ 2654 4473 l 2654 4462 l 2653 4451 l 2651 4442 l 2649 4432 l
+ 2647 4421 l 2644 4410 l 2641 4398 l 2637 4387 l 2633 4377 l
+ 2630 4368 l 2626 4359 l 2621 4351 l 2616 4342 l 2610 4334 l
+ 2604 4326 l 2597 4319 l 2591 4312 l 2584 4306 l 2577 4301 l
+ 2571 4296 l 2563 4291 l 2554 4286 l 2544 4281 l 2533 4276 l
+ 2521 4271 l 2509 4266 l 2496 4262 l 2483 4257 l 2471 4254 l
+ 2458 4250 l 2444 4247 l 2429 4244 l 2413 4240 l 2397 4237 l
+ 2381 4234 l 2365 4232 l 2351 4230 l 2337 4228 l 2325 4227 l
+ 2314 4226 l 2299 4225 l 2286 4225 l 2274 4226 l 2263 4228 l
+ 2253 4230 l 2245 4233 l 2238 4236 l
+ cp gs col20 1.00 shd ef gr gs col0 s gr
+7.500 slw
+% Rotated Ellipse
+gs
+3260 2603 tr
+-350.003 rot
+n 0 0 55 105 0 360 DrawEllipse 350.003 rot
+gs col7 1.00 shd ef gr gs col0 s gr
+gr
+
+% Polyline
+30.000 slw
+n 2246 4048 m 2247 4040 l 2248 4030 l 2251 4020 l 2254 4009 l 2259 3999 l
+ 2263 3989 l 2268 3983 l 2272 3976 l 2278 3969 l 2284 3963 l
+ 2291 3957 l 2298 3951 l 2304 3946 l 2311 3941 l 2317 3937 l
+ 2324 3932 l 2331 3928 l 2339 3924 l 2346 3920 l 2354 3916 l
+ 2362 3913 l 2369 3911 l 2377 3908 l 2385 3906 l 2394 3903 l
+ 2404 3901 l 2413 3899 l 2423 3898 l 2431 3896 l 2440 3896 l
+ 2448 3895 l 2456 3894 l 2465 3894 l 2474 3893 l 2483 3893 l
+ 2492 3893 l 2499 3893 l 2507 3892 l 2517 3892 l 2527 3892 l
+ 2538 3891 l 2548 3891 l 2558 3891 l 2567 3891 l 2576 3891 l
+ 2585 3892 l 2594 3893 l 2604 3895 l 2612 3897 l 2620 3899 l
+ 2628 3901 l 2637 3905 l 2646 3909 l 2655 3913 l 2665 3919 l
+ 2674 3925 l 2681 3929 l 2688 3935 l 2697 3941 l 2705 3948 l
+ 2713 3955 l 2721 3962 l 2727 3969 l 2733 3975 l 2738 3981 l
+ 2743 3988 l 2747 3996 l 2751 4003 l 2754 4011 l 2757 4019 l
+ 2759 4026 l 2761 4033 l 2763 4040 l 2765 4048 l 2767 4057 l
+ 2768 4066 l 2770 4076 l 2771 4085 l 2772 4095 l 2772 4105 l
+ 2773 4115 l 2773 4125 l 2772 4137 l 2771 4149 l 2770 4161 l
+ 2768 4173 l 2765 4184 l 2762 4193 l 2758 4202 l 2754 4211 l
+ 2748 4220 l 2741 4228 l 2733 4236 l 2725 4243 l 2717 4250 l
+ 2708 4255 l 2701 4259 l 2693 4263 l 2684 4267 l 2674 4270 l
+ 2664 4274 l 2654 4277 l 2643 4280 l 2633 4282 l 2622 4284 l
+ 2612 4286 l 2602 4287 l 2591 4288 l 2579 4289 l 2566 4290 l
+ 2553 4291 l 2540 4292 l 2527 4292 l 2515 4292 l 2503 4292 l
+ 2492 4292 l 2481 4291 l 2470 4291 l 2458 4290 l 2447 4289 l
+ 2435 4287 l 2423 4285 l 2412 4283 l 2402 4281 l 2392 4278 l
+ 2383 4275 l 2373 4270 l 2362 4265 l 2351 4259 l 2341 4251 l
+ 2331 4243 l 2322 4235 l 2314 4227 l 2306 4219 l 2299 4211 l
+ 2292 4202 l 2286 4192 l 2279 4182 l 2273 4172 l 2268 4162 l
+ 2264 4153 l 2261 4145 l 2257 4135 l 2254 4125 l 2252 4115 l
+ 2251 4106 l 2250 4098 l 2249 4091 l 2248 4085 l 2247 4078 l
+ 2246 4071 l 2246 4063 l 2246 4056 l
+ cp gs col20 1.00 shd ef gr gs col0 s gr
+% Polyline
+n 1481 6669 m 1482 6670 l 1487 6673 l 1499 6680 l 1516 6690 l 1534 6700 l
+ 1551 6710 l 1567 6719 l 1580 6726 l 1593 6732 l 1605 6737 l
+ 1615 6741 l 1626 6745 l 1637 6749 l 1649 6752 l 1661 6756 l
+ 1674 6759 l 1687 6762 l 1700 6765 l 1713 6767 l 1725 6770 l
+ 1737 6771 l 1749 6773 l 1762 6775 l 1774 6776 l 1788 6778 l
+ 1802 6779 l 1817 6780 l 1833 6781 l 1848 6782 l 1864 6783 l
+ 1879 6783 l 1894 6784 l 1908 6784 l 1922 6784 l 1934 6784 l
+ 1946 6784 l 1959 6784 l 1973 6784 l 1987 6784 l 2002 6783 l
+ 2017 6783 l 2032 6783 l 2047 6782 l 2062 6782 l 2077 6781 l
+ 2092 6780 l 2107 6780 l 2121 6779 l 2138 6779 l 2156 6778 l
+ 2175 6777 l 2194 6776 l 2213 6776 l 2232 6775 l 2250 6774 l
+ 2267 6773 l 2282 6773 l 2295 6772 l 2306 6772 l 2315 6771 l
+ 2317 6771 l 2319 6771 l 2321 6771 l 2323 6771 l 2325 6771 l
+ 2326 6771 l 2328 6771 l 2329 6771 l 2330 6771 l 2331 6771 l
+ 2332 6770 l 2333 6770 l 2334 6770 l 2335 6770 l 2334 6771 l
+ 2333 6771 l 2332 6771 l 2331 6771 l 2330 6771 l 2329 6771 l
+ 2328 6771 l
+ 2327 6771 l gs col0 s gr
+% Polyline
+n 3533 6267 m 3533 6268 l 3534 6275 l 3535 6289 l 3536 6305 l 3537 6320 l
+ 3538 6331 l 3538 6341 l 3538 6349 l 3536 6359 l 3535 6368 l
+ 3532 6377 l 3529 6385 l 3525 6392 l 3522 6398 l 3517 6404 l
+ 3512 6410 l 3506 6417 l 3500 6423 l 3493 6428 l 3486 6433 l
+ 3480 6436 l 3474 6440 l 3466 6443 l 3458 6447 l 3448 6450 l
+ 3439 6453 l 3429 6456 l 3419 6459 l 3410 6461 l 3400 6463 l
+ 3390 6466 l 3377 6469 l 3364 6472 l 3350 6476 l 3335 6480 l
+ 3319 6485 l 3304 6489 l 3287 6495 l 3275 6499 l 3261 6504 l
+ 3246 6509 l 3229 6516 l 3210 6523 l 3188 6531 l 3164 6541 l
+ 3139 6551 l 3114 6560 l 3091 6569 l 3075 6576 l 3064 6580 l
+ 3060 6582 l
+ 3059 6582 l gs col0 s gr
+% Polyline
+n 3983 6181 m 3983 6182 l 3983 6186 l 3984 6196 l 3986 6211 l 3987 6230 l
+ 3989 6250 l 3991 6268 l 3992 6284 l 3993 6299 l 3994 6311 l
+ 3995 6322 l 3996 6333 l 3997 6345 l 3997 6357 l 3998 6369 l
+ 3998 6380 l 3998 6392 l 3998 6403 l 3998 6413 l 3997 6423 l
+ 3997 6431 l 3996 6439 l 3994 6448 l 3991 6457 l 3988 6465 l
+ 3984 6474 l 3979 6481 l 3974 6488 l 3968 6494 l 3962 6499 l
+ 3955 6503 l 3947 6507 l 3937 6511 l 3927 6516 l 3915 6520 l
+ 3903 6523 l 3892 6527 l 3880 6531 l 3869 6533 l 3859 6537 l
+ 3847 6540 l 3834 6544 l 3821 6547 l 3807 6551 l 3793 6555 l
+ 3779 6558 l 3766 6561 l 3753 6564 l 3742 6566 l 3730 6569 l
+ 3718 6571 l 3704 6573 l 3690 6576 l 3675 6579 l 3660 6583 l
+ 3645 6586 l 3629 6590 l 3614 6595 l 3598 6599 l 3582 6604 l
+ 3570 6609 l 3557 6613 l 3543 6618 l 3528 6624 l 3511 6631 l
+ 3493 6639 l 3472 6648 l 3449 6658 l 3426 6668 l 3403 6679 l
+ 3381 6688 l 3363 6696 l 3350 6702 l 3343 6705 l
+ 3339 6707 l gs col0 s gr
+% Polyline
+n 2263 6883 m 2260 6890 l 2258 6899 l 2256 6908 l 2254 6916 l 2254 6925 l
+ 2253 6933 l 2253 6942 l 2252 6951 l 2252 6962 l 2252 6972 l
+ 2253 6982 l 2253 6991 l 2254 7000 l 2254 7009 l 2256 7018 l
+ 2257 7027 l 2259 7036 l 2262 7044 l 2264 7049 l 2267 7055 l
+ 2271 7062 l 2277 7069 l 2284 7076 l 2292 7084 l 2301 7091 l
+ 2312 7099 l 2320 7104 l 2330 7109 l 2340 7115 l 2352 7122 l
+ 2364 7128 l 2378 7135 l 2392 7142 l 2406 7148 l 2420 7155 l
+ 2433 7160 l 2446 7166 l 2459 7171 l 2472 7175 l 2485 7179 l
+ 2498 7184 l 2512 7188 l 2527 7192 l 2542 7195 l 2558 7199 l
+ 2574 7202 l 2590 7205 l 2606 7208 l 2623 7210 l 2639 7212 l
+ 2654 7214 l 2669 7215 l 2686 7217 l 2703 7219 l 2721 7220 l
+ 2741 7222 l 2760 7223 l 2780 7225 l 2799 7226 l 2818 7227 l
+ 2837 7229 l 2854 7230 l 2871 7231 l 2887 7232 l 2903 7232 l
+ 2919 7233 l 2935 7234 l 2951 7235 l 2968 7236 l 2985 7237 l
+ 3002 7237 l 3020 7238 l 3037 7239 l 3054 7240 l 3071 7240 l
+ 3088 7241 l 3104 7242 l 3121 7243 l 3135 7243 l 3151 7244 l
+ 3166 7244 l 3183 7245 l 3201 7246 l 3219 7246 l 3237 7247 l
+ 3256 7247 l 3274 7248 l 3293 7248 l 3311 7249 l 3328 7249 l
+ 3345 7249 l 3361 7249 l 3377 7249 l 3392 7249 l 3408 7249 l
+ 3425 7248 l 3442 7248 l 3459 7247 l 3476 7246 l 3494 7245 l
+ 3512 7244 l 3530 7242 l 3548 7241 l 3566 7239 l 3583 7238 l
+ 3600 7236 l 3617 7234 l 3634 7232 l 3649 7230 l 3664 7228 l
+ 3680 7226 l 3697 7224 l 3715 7222 l 3733 7220 l 3752 7217 l
+ 3771 7215 l 3789 7212 l 3807 7209 l 3825 7207 l 3842 7204 l
+ 3859 7202 l 3874 7199 l 3889 7197 l 3903 7195 l 3918 7192 l
+ 3933 7189 l 3948 7186 l 3963 7183 l 3978 7180 l 3993 7177 l
+ 4007 7174 l 4021 7171 l 4035 7167 l 4049 7164 l 4061 7160 l
+ 4074 7157 l 4085 7153 l 4097 7150 l 4109 7146 l 4121 7143 l
+ 4133 7138 l 4146 7134 l 4160 7129 l 4174 7124 l 4188 7119 l
+ 4203 7114 l 4217 7108 l 4232 7103 l 4246 7097 l 4260 7092 l
+ 4273 7086 l 4287 7081 l 4300 7075 l 4314 7070 l 4329 7063 l
+ 4344 7057 l 4359 7050 l 4375 7044 l 4391 7037 l 4407 7030 l
+ 4423 7023 l 4437 7017 l 4452 7010 l 4465 7004 l 4478 6999 l
+ 4490 6994 l 4503 6988 l 4516 6982 l 4529 6976 l 4542 6970 l
+ 4555 6964 l 4567 6959 l 4578 6954 l 4589 6949 l 4598 6944 l
+ 4607 6940 l 4615 6937 l 4622 6934 l 4634 6928 l 4644 6922 l
+ 4654 6917 l 4662 6912 l 4668 6907 l 4673 6902 l 4677 6897 l
+ 4682 6890 l 4686 6883 l 4689 6876 l 4692 6869 l 4694 6862 l
+ 4695 6856 l 4696 6849 l 4696 6842 l 4697 6835 l 4696 6828 l
+ 4696 6822 l 4695 6816 l 4695 6809 l 4694 6802 l 4693 6795 l
+ 4693 6788 l 4692 6782 l 4692 6775 l 4691 6768 l 4691 6760 l
+ 4690 6751 l 4690 6743 l 4689 6734 l 4688 6729 l 4688 6723 l
+ 4686 6717 l 4684 6712 l 4682 6706 l 4679 6701 l 4675 6698 l
+ 4671 6695 l 4666 6693 l 4660 6693 l 4653 6693 l 4645 6695 l
+ 4635 6699 l 4624 6703 l 4612 6709 l 4598 6715 l 4584 6722 l
+ 4570 6730 l 4556 6737 l 4542 6745 l 4529 6751 l 4516 6758 l
+ 4502 6765 l 4487 6772 l 4471 6779 l 4455 6787 l 4439 6794 l
+ 4424 6802 l 4408 6808 l 4394 6815 l 4380 6821 l 4368 6826 l
+ 4355 6831 l 4342 6836 l 4329 6841 l 4316 6846 l 4303 6851 l
+ 4289 6856 l 4276 6860 l 4262 6864 l 4250 6869 l 4237 6873 l
+ 4225 6876 l 4213 6880 l 4202 6883 l 4191 6886 l 4179 6890 l
+ 4167 6893 l 4154 6897 l 4140 6901 l 4126 6905 l 4111 6908 l
+ 4096 6912 l 4081 6916 l 4067 6919 l 4052 6923 l 4038 6926 l
+ 4023 6930 l 4008 6933 l 3992 6936 l 3976 6939 l 3959 6943 l
+ 3941 6946 l 3922 6950 l 3903 6953 l 3884 6957 l 3865 6960 l
+ 3846 6963 l 3829 6965 l 3812 6968 l 3795 6970 l 3780 6973 l
+ 3764 6974 l 3748 6976 l 3732 6978 l 3716 6980 l 3700 6982 l
+ 3683 6983 l 3666 6985 l 3649 6986 l 3633 6987 l 3617 6988 l
+ 3601 6989 l 3587 6990 l 3572 6991 l 3558 6992 l 3544 6993 l
+ 3529 6994 l 3514 6994 l 3498 6995 l 3481 6996 l 3463 6997 l
+ 3445 6997 l 3426 6998 l 3407 6999 l 3388 7000 l 3369 7000 l
+ 3350 7001 l 3331 7001 l 3312 7002 l 3296 7002 l 3280 7003 l
+ 3263 7003 l 3245 7004 l 3226 7004 l 3207 7005 l 3187 7005 l
+ 3167 7006 l 3146 7006 l 3125 7006 l 3104 7006 l 3084 7007 l
+ 3064 7007 l 3044 7007 l 3025 7007 l 3007 7007 l 2989 7007 l
+ 2972 7007 l 2953 7006 l 2934 7006 l 2915 7005 l 2895 7005 l
+ 2875 7004 l 2856 7003 l 2836 7002 l 2817 7001 l 2798 7000 l
+ 2780 6999 l 2763 6997 l 2746 6996 l 2731 6995 l 2717 6993 l
+ 2703 6992 l 2691 6991 l 2674 6988 l 2658 6986 l 2643 6984 l
+ 2628 6982 l 2613 6979 l 2598 6976 l 2584 6973 l 2571 6970 l
+ 2559 6967 l 2548 6965 l 2538 6962 l 2528 6959 l 2517 6956 l
+ 2505 6952 l 2493 6948 l 2482 6944 l 2470 6940 l 2459 6936 l
+ 2449 6932 l 2439 6928 l 2431 6924 l 2424 6920 l 2415 6915 l
+ 2406 6910 l 2398 6904 l 2390 6899 l 2382 6893 l 2375 6888 l
+ 2369 6883 l 2364 6878 l 2356 6872 l 2348 6866 l 2340 6860 l
+ 2332 6855 l 2325 6850 l 2320 6846 l 2316 6843 l 2312 6840 l
+ 2308 6838 l 2305 6836 l 2301 6835 l 2298 6835 l 2295 6836 l
+ 2292 6838 l 2287 6842 l 2282 6848 l 2276 6856 l 2271 6865 l
+ 2267 6874 l
+ cp gs col7 1.00 shd ef gr gs col0 s gr
+% Polyline
+n 3095 6246 m 3096 6246 l 3100 6246 l 3109 6246 l 3123 6247 l 3141 6248 l
+ 3159 6248 l 3177 6249 l 3193 6251 l 3207 6252 l 3220 6253 l
+ 3232 6255 l 3244 6257 l 3256 6260 l 3269 6263 l 3283 6266 l
+ 3299 6271 l 3317 6276 l 3337 6282 l 3358 6289 l 3378 6295 l
+ 3394 6301 l 3405 6304 l 3409 6306 l
+ 3410 6306 l gs col3 s gr
+% Polyline
+n 3599 6276 m 3600 6276 l 3605 6277 l 3616 6278 l 3633 6279 l 3654 6281 l
+ 3676 6283 l 3697 6285 l 3717 6287 l 3734 6289 l 3749 6291 l
+ 3763 6293 l 3777 6295 l 3791 6297 l 3805 6300 l 3821 6302 l
+ 3838 6306 l 3858 6309 l 3879 6314 l 3902 6318 l 3924 6323 l
+ 3942 6326 l 3953 6329 l 3958 6330 l
+ 3959 6330 l gs col3 s gr
+% Polyline
+15.000 slw
+n 4281 6302 m 4288 6296 l 4297 6291 l 4305 6287 l 4314 6283 l 4322 6281 l
+ 4330 6280 l 4337 6279 l 4344 6279 l 4352 6280 l 4359 6282 l
+ 4366 6284 l 4373 6287 l 4380 6290 l 4387 6294 l 4394 6300 l
+ 4401 6306 l 4408 6312 l 4414 6319 l 4420 6326 l 4426 6334 l
+ 4432 6343 l 4437 6353 l 4441 6363 l 4444 6373 l 4445 6380 l
+ 4446 6388 l 4447 6397 l 4447 6407 l 4446 6417 l 4445 6426 l
+ 4444 6435 l 4443 6444 l 4441 6452 l 4439 6461 l 4436 6470 l
+ 4433 6479 l 4430 6489 l 4426 6497 l 4422 6505 l 4418 6513 l
+ 4413 6519 l 4408 6526 l 4401 6533 l 4395 6540 l 4387 6546 l
+ 4380 6551 l 4373 6554 l 4366 6558 l 4357 6560 l 4346 6562 l
+ 4336 6562 l 4325 6561 l 4315 6559 l 4306 6557 l 4297 6554 l
+ 4288 6550 l 4279 6545 l 4271 6541 l 4263 6536 l 4257 6531 l
+ 4250 6526 l 4245 6521 l 4239 6516 l 4234 6510 l 4230 6504 l
+ 4227 6499 l 4224 6492 l 4221 6486 l 4219 6478 l 4218 6470 l
+ 4217 6462 l 4217 6454 l 4216 6446 l 4217 6437 l 4217 6428 l
+ 4218 6418 l 4220 6409 l 4221 6402 l 4223 6394 l 4224 6386 l
+ 4227 6378 l 4230 6370 l 4234 6361 l 4238 6354 l 4242 6347 l
+ 4246 6341 l 4251 6333 l 4257 6326 l 4263 6319 l 4269 6312 l
+ 4275 6306 l
+ cp gs col7 1.00 shd ef gr gs col0 s gr
+% Polyline
+30.000 slw
+n 3248 6546 m 3249 6546 l 3254 6546 l 3265 6547 l 3280 6548 l 3296 6550 l
+ 3312 6552 l 3326 6553 l 3338 6555 l 3349 6557 l 3359 6560 l
+ 3369 6562 l 3380 6566 l 3392 6570 l 3406 6576 l 3422 6582 l
+ 3438 6589 l 3453 6596 l 3464 6600 l 3469 6603 l
+ 3470 6603 l gs col3 s gr
+% Polyline
+n 3440 6504 m 3441 6504 l 3445 6504 l 3456 6504 l 3470 6504 l 3485 6504 l
+ 3500 6505 l 3513 6505 l 3525 6506 l 3535 6507 l 3545 6508 l
+ 3555 6510 l 3565 6512 l 3577 6515 l 3590 6518 l 3606 6523 l
+ 3622 6528 l 3637 6532 l 3647 6535 l 3652 6537 l
+ 3653 6537 l gs col3 s gr
+% Polyline
+n 3560 6402 m 3561 6402 l 3566 6403 l 3578 6404 l 3597 6405 l 3620 6407 l
+ 3644 6409 l 3666 6411 l 3686 6413 l 3704 6415 l 3720 6417 l
+ 3734 6419 l 3747 6421 l 3760 6423 l 3774 6425 l 3787 6428 l
+ 3803 6431 l 3819 6434 l 3838 6439 l 3857 6443 l 3875 6447 l
+ 3890 6451 l 3899 6453 l 3903 6454 l
+ 3904 6454 l gs col3 s gr
+% Polyline
+n 2861 6429 m 2863 6429 l 2866 6430 l 2872 6431 l 2881 6432 l 2887 6433 l
+ 2894 6434 l 2902 6435 l 2912 6437 l 2923 6439 l 2935 6442 l
+ 2947 6444 l 2959 6447 l 2971 6450 l 2983 6454 l 2993 6457 l
+ 3004 6460 l 3016 6464 l 3029 6469 l 3044 6474 l 3060 6480 l
+ 3078 6487 l 3095 6493 l 3109 6499 l 3117 6502 l 3121 6504 l
+
+ 3122 6504 l gs col3 s gr
+% Polyline
+n 2594 6492 m 2595 6492 l 2600 6492 l 2611 6493 l 2628 6493 l 2649 6494 l
+ 2671 6495 l 2692 6497 l 2712 6498 l 2729 6499 l 2745 6501 l
+ 2759 6502 l 2774 6504 l 2786 6506 l 2799 6508 l 2813 6511 l
+ 2828 6514 l 2845 6517 l 2864 6521 l 2884 6526 l 2906 6531 l
+ 2927 6536 l 2945 6540 l 2959 6543 l 2968 6545 l 2971 6546 l
+
+ 2972 6546 l gs col3 s gr
+% Polyline
+n 3023 6360 m 3024 6360 l 3028 6361 l 3037 6362 l 3052 6365 l 3070 6368 l
+ 3089 6371 l 3107 6374 l 3123 6377 l 3138 6380 l 3151 6383 l
+ 3163 6385 l 3175 6388 l 3187 6391 l 3200 6395 l 3213 6399 l
+ 3228 6403 l 3246 6409 l 3265 6415 l 3285 6421 l 3304 6428 l
+ 3320 6433 l 3330 6436 l 3334 6438 l
+ 3335 6438 l gs col3 s gr
+$F2psEnd
+rs
diff --git a/share/examples/BSD_daemon/beastie.fig b/share/examples/BSD_daemon/beastie.fig
new file mode 100644
index 000000000000..df03e83f4836
--- /dev/null
+++ b/share/examples/BSD_daemon/beastie.fig
@@ -0,0 +1,270 @@
+#FIG 3.2
+# SPDX-License-Identifier: Beerware
+#
+# ----------------------------------------------------------------------------
+# "THE BEER-WARE LICENSE" (Revision 42):
+# <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+# can do whatever you want with this stuff. If we meet some day, and you think
+# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+# ----------------------------------------------------------------------------
+#
+#
+Landscape
+Center
+Inches
+A4
+100.00
+Single
+-2
+1200 2
+1 1 0 1 0 0 47 0 20 0.000 1 6.0388 2748 2543 130 238 2748 2543 2878 2305
+1 1 0 1 0 7 46 0 20 0.000 1 6.1087 2738 2495 55 105 2738 2495 2793 2495
+1 1 0 1 0 0 47 0 20 0.000 1 6.0388 3291 2663 179 279 3291 2663 3470 2384
+1 1 0 1 0 7 46 0 20 0.000 1 6.1087 3260 2603 55 105 3260 2603 3315 2603
+3 0 0 3 0 7 49 0 -1 0.000 0 0 0 16
+ 4102 4658 4050 4695 4005 4703 3933 4706 3881 4706 3821 4688
+ 3746 4658 3671 4601 3615 4556 3536 4515 3450 4481 3333 4463
+ 3228 4459 3127 4481 3086 4511 2981 4574
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 0.000
+3 1 0 3 0 20 50 0 20 0.000 0 0 0 18
+ 2628 4864 2636 4898 2666 4928 2696 4939 2745 4943 2782 4950
+ 2812 4943 2895 4928 2943 4894 2973 4860 3011 4804 3052 4751
+ 3078 4729 3078 4695 3067 4661 3052 4628 3030 4594 3003 4553
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000
+3 1 0 3 0 20 47 0 20 0.000 0 0 0 21
+ 2250 4691 2302 4766 2358 4819 2403 4856 2478 4868 2565 4871
+ 2640 4856 2726 4834 2778 4808 2835 4748 2910 4665 2970 4594
+ 3000 4538 2996 4474 2985 4399 2925 4346 2868 4313 2801 4290
+ 2733 4290 2673 4305 2632 4346
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000
+3 1 0 3 0 20 46 0 20 0.000 0 0 0 19
+ 2287 4215 2231 4238 2182 4264 2141 4305 2096 4391 2096 4455
+ 2092 4534 2122 4598 2208 4665 2272 4680 2377 4688 2460 4691
+ 2561 4643 2636 4571 2651 4511 2658 4459 2632 4361 2591 4305
+ 2505 4256
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000
+3 1 0 3 0 20 45 0 20 0.000 0 0 0 20
+ 2250 4088 2242 4054 2257 3986 2310 3938 2366 3908 2441 3893
+ 2508 3893 2568 3889 2621 3896 2670 3919 2741 3975 2763 4031
+ 2775 4099 2771 4200 2715 4260 2617 4290 2490 4294 2377 4283
+ 2302 4223 2253 4140
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000
+3 0 0 3 0 7 49 0 -1 0.000 0 0 0 22
+ 2940 2986 2861 2930 2771 2915 2677 2919 2595 2960 2546 3020
+ 2531 3106 2535 3185 2583 3260 2647 3305 2718 3335 2805 3342
+ 2880 3342 2955 3331 3007 3320 3045 3324 3093 3357 3165 3350
+ 3202 3339 3210 3279 3195 3211 3157 3181
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 0.000
+3 0 0 3 0 7 50 0 -1 0.000 0 0 0 8
+ 2891 5190 2947 5209 3000 5228 3056 5235 3101 5239 3146 5239
+ 3187 5239 3187 5235
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 0.000
+3 0 0 3 0 7 50 0 -1 0.000 0 0 0 8
+ 2876 5202 2951 5306 3015 5351 3108 5404 3176 5419 3240 5434
+ 3315 5438 3352 5434
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 0.000
+3 0 0 3 0 7 50 0 -1 0.000 0 0 0 14
+ 3161 5427 3326 5528 3416 5546 3540 5565 3637 5535 3753 5501
+ 3862 5464 4005 5449 4132 5434 4293 5359 4421 5303 4533 5258
+ 4597 5198 4661 5093
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 0.000
+3 1 0 3 0 31 48 0 20 0.000 0 0 0 22
+ 3851 5483 4050 5625 4166 5696 4278 5768 4372 5831 4413 5854
+ 4447 5850 4473 5835 4488 5813 4515 5779 4526 5749 4522 5704
+ 4503 5678 4462 5648 4413 5618 4331 5565 4252 5513 4211 5494
+ 4121 5426 4121 5426 3993 5445 3866 5464
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000
+3 1 0 3 0 13 51 0 20 0.000 0 0 0 55
+ 2291 6462 2420 6447 2549 6444 2672 6444 2774 6441 2849 6387
+ 2951 6357 3026 6321 3068 6294 3059 6210 3026 6153 2996 6063
+ 2981 5991 3017 5991 3077 6030 3113 6075 3179 6057 3251 6060
+ 3308 6063 3347 6096 3392 6150 3455 6132 3500 6135 3521 6186
+ 3536 6255 3539 6309 3563 6237 3593 6159 3629 6090 3692 6060
+ 3764 6054 3827 6069 3893 6111 3956 6159 3980 6204 3983 6156
+ 4022 6138 4109 6138 4199 6132 4283 6102 4346 6081 4421 6042
+ 4466 6144 4523 6264 4583 6402 4625 6546 4667 6663 4682 6717
+ 4520 6837 4004 7044 3467 7131 2816 7128 2456 7047 2246 6816
+ 2006 6510
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+3 1 0 3 0 7 49 0 20 0.000 0 0 0 13
+ 3168 2255 3315 2009 3424 1894 3629 1784 3784 1943 3806 2158
+ 3786 2470 3693 2773 3553 2975 3328 3070 3103 2971 3034 2731
+ 3043 2543
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000
+3 0 0 3 0 7 45 0 -1 0.000 0 0 0 7
+ 1481 6669 1601 6744 1744 6777 1919 6787 2111 6780 2363 6769
+ 2327 6771
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+3 1 0 3 0 7 44 0 20 0.000 0 0 0 36
+ 2294 6825 2258 6885 2252 6930 2252 6993 2258 7044 2288 7092
+ 2462 7179 2618 7215 2900 7233 3104 7242 3407 7254 3617 7236
+ 3926 7194 4094 7155 4280 7086 4505 6987 4637 6927 4676 6906
+ 4697 6861 4697 6822 4691 6783 4691 6738 4679 6669 4553 6741
+ 4358 6834 4220 6879 4037 6930 3770 6978 3560 6993 3338 7002
+ 2957 7011 2666 6993 2522 6960 2414 6921 2363 6876 2315 6843
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000
+3 1 0 3 0 7 49 0 20 0.000 0 0 0 21
+ 2504 6663 2474 6609 2408 6552 2339 6501 2243 6477 2138 6471
+ 2006 6480 1874 6510 1669 6567 1475 6654 1418 6711 1397 6762
+ 1412 6843 1445 6921 1523 6978 1637 7017 1781 7029 1946 7032
+ 2069 7038 2177 7038 2321 7038
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000
+3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3
+ 3599 6276 3776 6291 3959 6330
+ 0.000 1.000 0.000
+3 1 0 2 0 7 43 0 20 0.000 0 0 0 14
+ 4232 6357 4280 6294 4331 6276 4373 6282 4415 6315 4451 6369
+ 4445 6444 4424 6516 4367 6567 4304 6561 4253 6531 4223 6501
+ 4214 6456 4220 6399
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000
+3 0 0 3 0 7 45 0 -1 0.000 0 0 0 7
+ 3533 6267 3542 6357 3524 6399 3491 6435 3428 6459 3309 6482
+ 3059 6582
+ 0.000 1.000 1.000 1.000 1.000 1.000 0.000
+3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3
+ 3440 6504 3544 6502 3653 6537
+ 0.000 1.000 0.000
+3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3
+ 3248 6546 3359 6552 3470 6603
+ 0.000 1.000 0.000
+3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3
+ 3560 6402 3755 6417 3904 6454
+ 0.000 1.000 0.000
+3 0 0 3 3 7 43 0 -1 0.000 0 0 0 4
+ 2861 6429 2861 6429 2979 6447 3122 6504
+ 0.000 1.000 1.000 0.000
+3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3
+ 2594 6492 2769 6497 2972 6546
+ 0.000 1.000 0.000
+3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3
+ 3023 6360 3173 6383 3335 6438
+ 0.000 1.000 0.000
+3 0 0 3 0 7 45 0 -1 0.000 0 0 0 8
+ 3983 6181 3998 6342 4001 6447 3971 6504 3887 6528 3758 6567
+ 3599 6588 3339 6707
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 0.000
+3 0 0 3 3 7 43 0 -1 0.000 0 0 0 3
+ 3095 6246 3240 6248 3410 6306
+ 0.000 1.000 0.000
+3 1 0 3 0 7 46 0 20 0.000 0 0 0 17
+ 2291 6976 2265 6844 2375 6738 2450 6702 2561 6645 2666 6612
+ 2795 6588 2915 6579 3029 6585 3152 6612 3239 6645 3320 6705
+ 3389 6786 3422 6876 3440 6984 3437 7056 2957 7152
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000
+3 0 0 4 0 7 49 0 -1 0.000 0 0 0 18
+ 2498 3459 2578 3459 2613 3489 2673 3554 2728 3614 2793 3669
+ 2853 3739 2948 3799 3053 3854 3173 3879 3328 3884 3453 3864
+ 3583 3799 3688 3749 3818 3669 3858 3614 3943 3609 3983 3609
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 0.000
+3 1 0 3 0 7 49 0 20 0.000 0 0 0 17
+ 2786 2845 2877 2727 2925 2661 3009 2376 3075 2175 3131 2050
+ 3174 1929 3192 1869 3114 1746 2940 1824 2871 1890 2712 2103
+ 2598 2340 2562 2427 2538 2709 2616 2814 2679 2850
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000
+3 1 0 3 0 20 52 0 20 0.000 0 0 0 142
+ 2136 3087 2170 2963 2229 2861 2391 2682 2418 2498 2498 2228
+ 2476 2126 2452 2000 2401 1725 2407 1577 2476 1395 2483 1365
+ 2719 1094 2978 878 3235 725 3394 659 3490 731 3394 806
+ 3277 932 3166 1080 3112 1163 3103 1253 3112 1364 3151 1425
+ 3235 1418 3397 1334 3616 1277 3871 1265 4150 1298 4628 1478
+ 4793 1646 4861 1725 5006 1706 5273 1568 5288 1490 5281 1223
+ 5141 998 5101 908 5189 866 5326 893 5465 1010 5708 1328
+ 5789 1577 5836 1830 5765 2093 5513 2438 5207 2654 5056 2760
+ 5078 2729 5072 3058 4988 3368 4829 3607 4565 3850 4502 3970
+ 4486 4088 4511 4213 4589 4330 4643 4455 4679 4633 4688 4958
+ 4667 5107 4607 5230 4613 5344 4733 5685 4928 5985 5221 6195
+ 5570 6348 5993 6443 6480 6542 6773 6623 6966 6698 7141 6825
+ 7206 6977 7208 7110 7062 7250 6923 7320 6513 7397 6481 7403
+ 6518 7493 6468 7502 6120 7505 5571 7526 5298 7547 5241 7532
+ 5298 7487 5958 7130 6174 6998 6249 6935 6291 6995 6342 7076
+ 6368 7155 6408 7205 6608 7170 6756 7115 6878 7035 6873 6959
+ 6750 6851 6543 6779 5985 6713 5568 6632 5271 6554 5003 6462
+ 4821 6389 4673 6278 4545 6194 4431 6068 4371 6089 3675 6375
+ 3016 5993 2997 5942 2859 5732 2802 5591 2798 5438 2820 5318
+ 2873 5220 2883 5186 2856 5153 2778 5075 2768 4988 2791 4943
+ 2701 4943 2661 4925 2633 4883 2577 4868 2273 4422 2457 4299
+ 2763 4274 3001 4305 3128 4328 3203 4230 3216 4124 3173 4028
+ 3081 3995 2986 3945 2880 3851 2733 3770 2634 3698 2493 3665
+ 2334 3566 2221 3413 2166 3323 2133 3179
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000
+3 0 0 3 0 7 49 0 -1 0.000 0 0 0 5
+ 3489 1649 3649 1554 3825 1575 3953 1675 4005 1902
+ 0.000 1.000 1.000 1.000 0.000
+3 0 0 3 0 7 49 0 -1 0.000 0 0 0 10
+ 3278 1680 3254 1569 3149 1539 3009 1544 2883 1665 2696 1865
+ 2564 2129 2505 2334 2441 2484 2379 2670
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 0.000
+3 0 0 3 0 31 51 0 20 0.000 0 0 0 71
+ 2452 4170 2238 4009 2122 3911 2078 3867 2096 3836 2128 3795
+ 2148 3725 2153 3675 2151 3587 2131 3510 2101 3423 2013 3341
+ 1954 3332 2041 3258 1914 3207 1843 3180 1773 3140 1668 3097
+ 1557 3040 1621 3132 1671 3192 1718 3287 1753 3350 1783 3475
+ 1836 3430 1891 3385 1943 3442 2003 3515 2021 3595 2023 3642
+ 2006 3702 1953 3735 1921 3767 1873 3730 1833 3695 1791 3665
+ 1738 3622 1669 3576 1731 3501 1731 3474 1529 3466 1222 3248
+ 1344 3469 1433 3645 1446 3735 1468 3765 1503 3740 1563 3675
+ 1616 3722 1703 3792 1758 3842 1786 3927 1718 3977 1518 4045
+ 1229 3950 1297 3894 1364 3856 1357 3792 1147 3759 903 3564
+ 884 3646 1008 3875 1218 4119 1413 4179 1641 4200 1796 4130
+ 1926 4060 1956 4027 2076 4125 2216 4253 2332 4339
+ 0.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
+ 1.000 1.000 1.000 1.000 1.000 1.000 0.000
diff --git a/share/examples/BSD_daemon/beastie.svg b/share/examples/BSD_daemon/beastie.svg
new file mode 100644
index 000000000000..9d16e3da42a5
--- /dev/null
+++ b/share/examples/BSD_daemon/beastie.svg
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="283.464567pt" height="283.464567pt" viewBox="0 0 283.464567 283.464567" version="1.1">
+<g style="stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;stroke-linecap:butt;stroke-linejoin:miter;fill:none;fill-rule:nonzero;fill-opacity:1;stroke-width:30;" transform="matrix(0.035,0,0,0.035,0,0)">
+<path style="fill:rgb(82%,0%,0%);" d="M 2174 2967 l 5 -11 l 4 -10 l 6 -11 l 6 -12 l 7 -12 l 8 -13 l 9 -12 l 8 -13 l 9 -12 l 10 -13 l 8 -9 l 8 -10 l 8 -11 l 10 -11 l 9 -12 l 10 -12 l 10 -13 l 10 -14 l 10 -13 l 9 -13 l 9 -12 l 8 -13 l 7 -12 l 7 -12 l 5 -12 l 6 -12 l 5 -13 l 5 -13 l 4 -14 l 5 -14 l 4 -15 l 3 -15 l 4 -15 l 4 -15 l 3 -15 l 3 -15 l 3 -15 l 4 -14 l 3 -15 l 4 -16 l 5 -17 l 4 -17 l 5 -18 l 4 -18 l 5 -18 l 4 -18 l 5 -18 l 4 -16 l 3 -16 l 3 -15 l 3 -13 l 2 -13 l 2 -16 l 2 -16 l 0 -44 l -2 -13 l -1 -12 l -2 -12 l -2 -11 l -2 -10 l -2 -9 l -2 -9 l -2 -10 l -2 -11 l -2 -12 l -3 -12 l -2 -13 l -3 -14 l -2 -13 l -3 -14 l -3 -15 l -2 -15 l -3 -13 l -3 -15 l -3 -15 l -2 -16 l -4 -18 l -6 -36 l -3 -18 l -3 -18 l -2 -18 l -3 -17 l -2 -16 l -2 -15 l -1 -14 l -2 -16 l -1 -15 l -1 -16 l -1 -15 l 0 -16 l 1 -15 l 1 -15 l 2 -28 l 2 -13 l 3 -13 l 3 -13 l 3 -12 l 3 -14 l 4 -13 l 4 -15 l 5 -14 l 5 -14 l 4 -14 l 5 -13 l 4 -12 l 4 -11 l 4 -10 l 3 -9 l 3 -9 l 6 -16 l 4 -9 l 4 -8 l 6 -9 l 6 -10 l 7 -10 l 9 -11 l 10 -13 l 8 -9 l 8 -10 l 9 -11 l 10 -12 l 12 -13 l 12 -15 l 13 -14 l 14 -16 l 14 -16 l 15 -16 l 15 -15 l 14 -16 l 15 -15 l 14 -15 l 54 -54 l 14 -12 l 13 -13 l 14 -12 l 15 -13 l 15 -13 l 15 -13 l 15 -13 l 15 -13 l 15 -12 l 15 -13 l 15 -11 l 15 -11 l 14 -11 l 13 -10 l 13 -10 l 14 -9 l 14 -11 l 16 -10 l 15 -11 l 16 -10 l 16 -11 l 16 -10 l 17 -11 l 16 -10 l 17 -10 l 15 -9 l 16 -9 l 15 -9 l 14 -8 l 13 -7 l 13 -7 l 12 -6 l 15 -9 l 16 -7 l 15 -8 l 16 -7 l 15 -6 l 15 -6 l 14 -5 l 14 -4 l 12 -3 l 12 -2 l 11 -1 l 10 0 l 9 1 l 9 1 l 10 3 l 8 3 l 9 4 l 7 4 l 7 5 l 5 6 l 5 6 l 3 5 l 2 12 l -1 6 l -2 7 l -5 8 l -6 8 l -7 9 l -8 9 l -10 9 l -9 9 l -10 8 l -9 10 l -9 7 l -8 9 l -9 9 l -10 10 l -10 10 l -10 11 l -10 11 l -10 11 l -10 11 l -9 11 l -9 10 l -9 11 l -9 10 l -9 11 l -9 12 l -9 12 l -10 12 l -9 12 l -9 12 l -9 12 l -8 11 l -8 10 l -7 10 l -6 9 l -8 11 l -7 10 l -7 10 l -6 10 l -7 10 l -5 10 l -5 9 l -5 9 l -3 8 l -3 8 l -4 10 l -3 11 l -2 11 l -2 13 l -1 12 l -1 12 l -1 12 l 0 23 l 1 13 l 0 13 l 2 14 l 1 13 l 2 13 l 2 11 l 3 11 l 3 9 l 4 10 l 4 8 l 5 9 l 6 7 l 6 6 l 7 5 l 7 4 l 7 2 l 9 2 l 10 1 l 11 -1 l 12 -2 l 13 -2 l 13 -4 l 14 -5 l 10 -4 l 10 -4 l 12 -5 l 12 -5 l 13 -6 l 14 -6 l 15 -7 l 14 -6 l 15 -6 l 15 -6 l 14 -6 l 15 -5 l 12 -5 l 13 -5 l 14 -4 l 15 -5 l 15 -4 l 16 -5 l 17 -4 l 16 -4 l 17 -4 l 17 -3 l 16 -4 l 16 -3 l 16 -2 l 15 -2 l 16 -3 l 16 -2 l 17 -1 l 17 -2 l 19 -2 l 57 -3 l 20 0 l 19 -1 l 19 0 l 18 1 l 18 0 l 17 1 l 15 0 l 16 1 l 17 1 l 17 2 l 18 1 l 18 3 l 20 2 l 20 3 l 20 3 l 63 12 l 42 10 l 21 6 l 21 6 l 36 10 l 19 6 l 19 6 l 42 14 l 21 7 l 22 8 l 22 9 l 22 8 l 44 18 l 21 8 l 21 9 l 19 9 l 19 8 l 18 9 l 17 8 l 16 8 l 15 8 l 20 11 l 20 12 l 18 12 l 18 12 l 17 12 l 17 12 l 15 13 l 14 12 l 13 11 l 12 11 l 11 10 l 9 10 l 9 9 l 8 8 l 10 11 l 10 11 l 10 10 l 10 9 l 10 9 l 9 8 l 10 7 l 9 5 l 9 4 l 10 4 l 8 2 l 9 1 l 11 1 l 11 0 l 12 -1 l 13 -2 l 14 -2 l 14 -3 l 15 -4 l 15 -4 l 15 -5 l 15 -6 l 14 -5 l 15 -6 l 15 -7 l 16 -7 l 17 -8 l 17 -9 l 16 -8 l 17 -9 l 16 -9 l 15 -9 l 14 -8 l 12 -8 l 11 -8 l 10 -7 l 10 -8 l 9 -8 l 8 -9 l 6 -8 l 6 -9 l 8 -20 l 2 -11 l 2 -11 l 1 -11 l 1 -12 l 0 -12 l 1 -12 l 0 -13 l -1 -14 l 0 -15 l -1 -17 l -1 -17 l -1 -18 l -2 -18 l -2 -19 l -6 -36 l -4 -17 l -4 -17 l -4 -16 l -5 -16 l -6 -16 l -7 -17 l -7 -16 l -7 -17 l -8 -17 l -9 -16 l -8 -17 l -9 -15 l -8 -14 l -7 -14 l -8 -12 l -6 -12 l -6 -10 l -8 -14 l -7 -14 l -7 -12 l -5 -12 l -5 -12 l -3 -10 l -2 -9 l -1 -9 l 1 -7 l 1 -6 l 3 -6 l 4 -5 l 6 -6 l 6 -5 l 8 -4 l 9 -4 l 9 -3 l 10 -3 l 10 -1 l 10 -1 l 11 -1 l 11 0 l 13 1 l 13 2 l 14 3 l 14 4 l 14 4 l 13 5 l 14 6 l 12 6 l 9 5 l 10 5 l 9 7 l 11 7 l 10 8 l 11 9 l 12 9 l 12 11 l 12 11 l 12 12 l 12 12 l 12 12 l 12 14 l 12 14 l 10 11 l 10 12 l 11 13 l 11 13 l 12 15 l 12 15 l 12 16 l 13 16 l 12 17 l 13 17 l 12 17 l 12 17 l 11 17 l 11 16 l 10 16 l 9 15 l 10 15 l 8 15 l 9 16 l 9 16 l 8 16 l 8 17 l 8 17 l 7 17 l 7 18 l 7 17 l 6 17 l 6 17 l 6 17 l 5 16 l 4 16 l 5 15 l 4 14 l 3 15 l 4 14 l 3 15 l 4 15 l 3 15 l 3 16 l 4 17 l 2 17 l 3 17 l 2 17 l 2 17 l 2 16 l 1 17 l 1 15 l 0 31 l -1 15 l -1 15 l -1 15 l -2 15 l -2 16 l -3 17 l -4 18 l -4 17 l -5 19 l -6 18 l -6 18 l -7 19 l -7 18 l -8 18 l -16 34 l -9 18 l -9 15 l -9 16 l -10 17 l -10 17 l -11 18 l -12 18 l -13 19 l -14 18 l -13 19 l -15 19 l -14 19 l -15 18 l -14 18 l -15 17 l -14 16 l -15 16 l -14 15 l -14 15 l -14 14 l -15 14 l -15 13 l -15 14 l -16 14 l -17 14 l -16 14 l -17 13 l -17 13 l -16 13 l -16 13 l -16 11 l -15 12 l -15 10 l -14 10 l -13 9 l -12 9 l -12 9 l -17 12 l -17 11 l -16 12 l -15 10 l -15 11 l -14 9 l -13 9 l -11 8 l -10 6 l -8 6 l -7 4 l -5 3 l -4 2 l -6 4 l -2 1 l -1 2 l -1 1 l -1 3 l 0 6 l 1 5 l 0 5 l 1 6 l 1 8 l 0 9 l 1 9 l 0 67 l -1 18 l 0 18 l -1 20 l -2 19 l -1 20 l -2 19 l -1 20 l -2 19 l -3 18 l -2 19 l -3 18 l -3 19 l -3 19 l -4 19 l -4 20 l -5 20 l -5 20 l -6 21 l -5 20 l -6 20 l -7 19 l -6 19 l -6 18 l -7 17 l -7 16 l -6 16 l -8 16 l -7 15 l -8 16 l -9 16 l -9 17 l -10 16 l -10 17 l -11 17 l -11 17 l -11 16 l -12 16 l -11 15 l -12 15 l -12 15 l -12 14 l -11 14 l -13 14 l -13 14 l -13 14 l -14 15 l -15 15 l -14 15 l -16 15 l -15 16 l -15 15 l -14 15 l -40 40 l -11 12 l -11 11 l -9 11 l -12 13 l -11 13 l -11 13 l -9 13 l -9 13 l -8 12 l -7 12 l -6 11 l -5 11 l -8 20 l -3 9 l -4 11 l -3 11 l -2 12 l -3 12 l -2 13 l -2 13 l -1 12 l 0 46 l 1 12 l 2 12 l 2 13 l 3 13 l 3 14 l 3 13 l 4 12 l 4 11 l 5 12 l 5 11 l 5 11 l 7 12 l 6 13 l 8 13 l 7 12 l 7 13 l 7 12 l 7 11 l 6 11 l 6 12 l 6 11 l 6 13 l 6 13 l 6 14 l 6 14 l 5 14 l 5 14 l 5 14 l 4 14 l 3 10 l 3 11 l 3 11 l 3 12 l 2 13 l 3 13 l 3 15 l 3 14 l 2 16 l 2 15 l 2 16 l 2 15 l 2 16 l 2 17 l 1 14 l 1 16 l 1 16 l 1 17 l 1 18 l 1 18 l 1 19 l 0 19 l 1 19 l 0 37 l 1 17 l 0 16 l -1 16 l 0 29 l -1 17 l 0 17 l -1 17 l -2 16 l -1 16 l -2 16 l -2 15 l -3 13 l -2 13 l -3 12 l -3 11 l -2 11 l -4 12 l -5 13 l -4 13 l -5 13 l -5 14 l -5 13 l -5 13 l -4 12 l -3 12 l -3 11 l -2 9 l -1 9 l -1 10 l -1 11 l 0 12 l 1 12 l 2 13 l 2 14 l 2 15 l 4 15 l 4 16 l 4 17 l 4 13 l 4 15 l 5 15 l 5 17 l 6 18 l 7 19 l 7 19 l 7 21 l 8 21 l 8 20 l 9 21 l 8 21 l 9 19 l 9 20 l 9 19 l 9 18 l 8 16 l 8 17 l 9 16 l 9 17 l 10 18 l 11 17 l 11 18 l 11 17 l 11 18 l 12 17 l 13 17 l 12 17 l 12 16 l 12 15 l 13 15 l 12 14 l 12 14 l 12 13 l 26 26 l 14 13 l 14 12 l 15 13 l 15 14 l 16 13 l 17 13 l 17 13 l 17 12 l 18 13 l 17 12 l 17 11 l 17 11 l 17 10 l 17 11 l 16 9 l 16 10 l 17 9 l 17 9 l 17 9 l 18 9 l 19 10 l 19 9 l 20 9 l 21 10 l 21 9 l 42 18 l 21 8 l 21 8 l 20 8 l 20 7 l 40 14 l 19 6 l 36 12 l 19 5 l 19 6 l 20 5 l 21 6 l 21 5 l 22 6 l 22 6 l 23 5 l 22 6 l 46 10 l 22 6 l 23 5 l 21 4 l 22 5 l 21 5 l 21 4 l 21 5 l 21 4 l 21 5 l 22 4 l 22 5 l 23 5 l 23 5 l 24 5 l 25 5 l 24 5 l 24 5 l 25 5 l 24 5 l 46 10 l 22 5 l 21 5 l 20 4 l 20 5 l 19 4 l 18 4 l 22 5 l 21 5 l 22 6 l 22 5 l 21 5 l 22 6 l 21 5 l 21 6 l 20 5 l 19 6 l 19 5 l 17 5 l 17 5 l 15 5 l 15 5 l 14 4 l 32 10 l 15 6 l 16 5 l 16 6 l 16 6 l 16 7 l 15 6 l 15 6 l 15 7 l 13 6 l 13 7 l 13 6 l 12 7 l 12 6 l 12 8 l 13 7 l 12 8 l 13 9 l 13 9 l 13 9 l 12 10 l 12 10 l 11 9 l 10 10 l 10 9 l 9 9 l 8 9 l 9 11 l 8 11 l 8 12 l 8 12 l 7 13 l 7 13 l 6 13 l 5 13 l 5 13 l 3 11 l 4 12 l 3 11 l 2 13 l 2 13 l 2 14 l 1 15 l -1 14 l -1 15 l -3 14 l -4 14 l -5 13 l -6 12 l -6 11 l -7 10 l -8 12 l -9 11 l -10 12 l -11 12 l -12 11 l -12 11 l -11 10 l -12 10 l -11 9 l -11 8 l -9 7 l -10 7 l -10 6 l -11 7 l -11 6 l -13 6 l -13 7 l -13 6 l -15 5 l -15 6 l -15 5 l -16 5 l -17 5 l -17 5 l -16 4 l -18 5 l -18 4 l -20 5 l -20 4 l -22 5 l -22 4 l -22 5 l -21 4 l -22 5 l -20 4 l -19 3 l -18 4 l -16 3 l -15 3 l -13 2 l -16 3 l -14 3 l -12 2 l -10 3 l -9 2 l -8 2 l -5 3 l -4 2 l -3 3 l -2 3 l 0 6 l 1 8 l 2 11 l 3 12 l 3 12 l 2 11 l 0 9 l -2 4 l -2 3 l -3 4 l -6 2 l -7 2 l -9 2 l -11 2 l -14 1 l -15 0 l -17 1 l -10 0 l -12 1 l -41 0 l -17 1 l -36 0 l -20 1 l -20 0 l -21 1 l -43 0 l -22 1 l -22 0 l -23 1 l -22 0 l -22 1 l -21 1 l -22 0 l -22 1 l -23 1 l -24 0 l -24 1 l -26 1 l -25 1 l -27 1 l -78 3 l -50 2 l -46 2 l -22 1 l -21 1 l -20 1 l -19 1 l -46 2 l -22 2 l -21 1 l -22 1 l -21 1 l -20 2 l -19 1 l -18 1 l -18 1 l -16 1 l -14 0 l -13 1 l -12 0 l -11 1 l -37 0 l -11 -1 l -10 -1 l -9 -1 l -7 -2 l -4 -2 l -4 -2 l -1 -2 l -1 -3 l 0 -2 l 2 -3 l 3 -4 l 5 -4 l 7 -6 l 9 -6 l 12 -8 l 15 -9 l 17 -11 l 20 -12 l 23 -13 l 26 -14 l 15 -9 l 17 -9 l 18 -10 l 19 -11 l 20 -11 l 22 -12 l 23 -12 l 23 -13 l 25 -14 l 25 -13 l 26 -15 l 25 -14 l 26 -14 l 25 -14 l 25 -13 l 25 -14 l 23 -13 l 23 -12 l 21 -12 l 21 -11 l 19 -11 l 19 -10 l 24 -14 l 24 -13 l 22 -13 l 21 -12 l 21 -12 l 20 -12 l 19 -11 l 17 -10 l 17 -10 l 15 -9 l 14 -9 l 13 -8 l 11 -7 l 11 -7 l 9 -6 l 9 -5 l 12 -9 l 12 -8 l 12 -8 l 10 -8 l 10 -6 l 10 -6 l 8 -4 l 7 -3 l 6 -2 l 11 0 l 5 1 l 5 3 l 5 4 l 5 4 l 15 18 l 4 6 l 5 7 l 5 8 l 6 9 l 6 10 l 6 10 l 6 10 l 6 11 l 5 9 l 5 10 l 4 9 l 4 10 l 5 10 l 4 10 l 4 10 l 4 9 l 4 8 l 3 8 l 3 6 l 4 6 l 4 5 l 5 5 l 6 5 l 7 5 l 7 3 l 9 3 l 9 2 l 11 1 l 20 0 l 12 -1 l 14 -1 l 14 -2 l 15 -2 l 16 -2 l 16 -3 l 15 -3 l 15 -4 l 14 -3 l 13 -3 l 14 -4 l 13 -4 l 13 -4 l 14 -4 l 14 -5 l 13 -5 l 14 -5 l 12 -5 l 13 -5 l 11 -5 l 11 -5 l 11 -5 l 12 -7 l 12 -6 l 13 -8 l 12 -7 l 12 -8 l 12 -9 l 10 -8 l 9 -8 l 7 -7 l 6 -7 l 4 -6 l 3 -6 l 3 -7 l 2 -7 l 1 -6 l 0 -8 l -1 -7 l -2 -7 l -2 -7 l -3 -7 l -4 -7 l -10 -14 l -6 -8 l -7 -8 l -9 -8 l -9 -9 l -10 -9 l -11 -9 l -12 -8 l -11 -9 l -12 -8 l -13 -7 l -12 -7 l -20 -10 l -11 -5 l -11 -5 l -13 -6 l -14 -5 l -15 -5 l -16 -5 l -16 -5 l -36 -10 l -19 -4 l -19 -5 l -20 -4 l -20 -4 l -21 -4 l -18 -3 l -19 -3 l -20 -4 l -21 -3 l -23 -3 l -23 -4 l -24 -3 l -25 -4 l -26 -4 l -27 -3 l -27 -4 l -26 -4 l -27 -3 l -26 -4 l -26 -3 l -25 -4 l -24 -3 l -24 -4 l -23 -3 l -22 -3 l -23 -4 l -22 -3 l -44 -8 l -23 -3 l -23 -4 l -23 -4 l -23 -4 l -23 -5 l -22 -4 l -23 -4 l -22 -4 l -21 -4 l -21 -5 l -20 -4 l -19 -4 l -18 -3 l -17 -4 l -17 -4 l -17 -3 l -20 -5 l -21 -5 l -20 -4 l -20 -5 l -21 -5 l -21 -6 l -42 -10 l -21 -6 l -20 -5 l -19 -5 l -19 -6 l -18 -5 l -17 -5 l -17 -4 l -32 -10 l -17 -5 l -16 -5 l -17 -6 l -18 -5 l -17 -6 l -18 -6 l -17 -6 l -18 -6 l -17 -6 l -16 -5 l -16 -6 l -15 -5 l -14 -5 l -14 -5 l -13 -5 l -14 -5 l -15 -6 l -14 -5 l -15 -6 l -15 -6 l -15 -6 l -14 -6 l -15 -6 l -13 -6 l -14 -6 l -12 -6 l -12 -6 l -11 -6 l -11 -6 l -13 -8 l -13 -7 l -13 -8 l -26 -18 l -14 -9 l -13 -9 l -13 -9 l -12 -9 l -12 -8 l -11 -8 l -11 -7 l -10 -8 l -11 -7 l -11 -8 l -11 -8 l -12 -8 l -11 -8 l -12 -9 l -11 -8 l -10 -8 l -11 -8 l -9 -8 l -10 -8 l -11 -10 l -11 -10 l -12 -11 l -12 -11 l -11 -12 l -12 -10 l -11 -10 l -10 -8 l -9 -7 l -8 -5 l -7 -4 l -6 -3 l -8 -1 l -9 -1 l -10 2 l -12 2 l -15 4 l -17 5 l -19 7 l -21 9 l -24 9 l -27 11 l -15 6 l -16 7 l -17 7 l -19 7 l -19 7 l -21 8 l -22 8 l -24 8 l -24 8 l -26 8 l -26 8 l -27 8 l -27 7 l -28 7 l -28 6 l -29 5 l -28 5 l -28 4 l -27 4 l -27 2 l -27 2 l -53 0 l -26 -1 l -26 -3 l -26 -3 l -26 -4 l -26 -6 l -27 -6 l -27 -7 l -27 -8 l -27 -9 l -28 -10 l -27 -10 l -27 -11 l -52 -22 l -25 -12 l -24 -12 l -23 -11 l -21 -12 l -21 -11 l -20 -11 l -18 -11 l -17 -10 l -15 -9 l -15 -9 l -13 -9 l -21 -13 l -19 -13 l -16 -11 l -15 -11 l -13 -10 l -11 -10 l -9 -9 l -9 -8 l -7 -8 l -6 -8 l -5 -8 l -5 -7 l -10 -16 l -5 -9 l -6 -10 l -7 -11 l -7 -12 l -8 -12 l -8 -13 l -9 -14 l -9 -14 l -8 -14 l -8 -14 l -8 -13 l -8 -13 l -7 -12 l -6 -11 l -8 -14 l -7 -13 l -6 -13 l -7 -14 l -6 -14 l -5 -13 l -6 -14 l -4 -13 l -4 -12 l -4 -12 l -3 -12 l -2 -11 l -2 -11 l -2 -12 l -2 -12 l -1 -13 l -1 -13 l -1 -13 l -1 -13 l 0 -37 l 1 -11 l 0 -10 l 1 -13 l 2 -13 l 1 -12 l 2 -14 l 2 -13 l 3 -13 l 3 -12 l 3 -11 l 3 -11 l 3 -10 l 5 -13 l 5 -12 l 5 -13 l 6 -13 l 6 -12 l 5 -11 l 5 -9 l 4 -8 l 4 -10 l 4 -9 l 2 -7 l 1 -8 l 1 -6 l -1 -5 l -2 -5 l -3 -6 l -5 -7 l -5 -7 l -7 -7 l -7 -8 l -7 -7 l -7 -8 l -8 -9 l -9 -9 l -8 -10 l -7 -10 l -7 -10 l -6 -9 l -4 -10 l -4 -10 l -3 -11 l -3 -11 l -1 -10 l -1 -10 l 0 -9 l 1 -8 l 0 -7 l 2 -7 l 1 -7 l 1 -6 l 0 -6 l -1 -5 l -2 -4 l -3 -2 l -6 -3 l -10 -3 l -11 -1 l -13 -2 l -12 -1 l -11 -1 l -9 -2 l -9 -2 l -9 -3 l -14 -8 l -5 -4 l -5 -5 l -6 -6 l -5 -6 l -6 -6 l -6 -6 l -7 -4 l -4 -3 l -4 -3 l -6 -4 l -7 -5 l -8 -7 l -10 -9 l -11 -11 l -13 -14 l -14 -16 l -15 -20 l -10 -12 l -10 -14 l -11 -15 l -12 -16 l -12 -17 l -12 -19 l -13 -20 l -13 -20 l -12 -20 l -13 -21 l -11 -21 l -11 -21 l -10 -19 l -9 -19 l -8 -18 l -6 -17 l -5 -16 l -4 -15 l -2 -13 l -1 -12 l 0 -12 l 1 -11 l 2 -11 l 3 -10 l 4 -10 l 5 -9 l 6 -9 l 7 -9 l 8 -8 l 8 -7 l 9 -7 l 10 -6 l 10 -5 l 10 -6 l 11 -4 l 10 -4 l 11 -4 l 11 -4 l 15 -4 l 15 -4 l 15 -3 l 17 -3 l 17 -3 l 36 -6 l 19 -2 l 19 -2 l 19 -1 l 19 -2 l 18 -1 l 17 0 l 17 -1 l 32 0 l 17 1 l 18 0 l 54 3 l 19 2 l 18 2 l 17 1 l 17 2 l 16 2 l 15 2 l 14 2 l 13 2 l 13 2 l 32 4 l 15 3 l 16 1 l 15 2 l 27 0 l 11 -1 l 11 -2 l 9 -3 l 9 -4 l 9 -5 l 9 -7 l 9 -7 l 8 -9 l 7 -9 l 7 -10 l 6 -9 l 5 -10 l 5 -9 l 3 -10 l 4 -10 l 3 -10 l 2 -11 l 2 -11 l 1 -11 l 0 -31 l -1 -9 l -2 -12 l -4 -12 l -4 -12 l -5 -12 l -6 -12 l -7 -10 l -7 -10 l -15 -15 l -10 -6 l -10 -6 l -11 -6 l -12 -6 l -12 -5 l -11 -5 l -10 -5 l -9 -4 l -9 -4 l -10 -5 l -10 -5 l -10 -5 l -10 -6 l -10 -6 l -10 -7 l -10 -6 l -9 -6 l -9 -7 l -10 -8 l -10 -8 l -12 -9 l -11 -9 l -12 -9 l -12 -9 l -12 -9 l -11 -9 l -12 -8 l -10 -7 l -10 -6 l -11 -7 l -11 -7 l -12 -8 l -12 -7 l -12 -7 l -12 -7 l -12 -7 l -10 -6 l -10 -7 l -10 -5 l -11 -8 l -11 -7 l -12 -7 l -11 -7 l -12 -8 l -12 -7 l -12 -7 l -11 -6 l -11 -5 l -11 -5 l -9 -4 l -10 -4 l -11 -4 l -11 -4 l -12 -4 l -12 -4 l -12 -4 l -13 -5 l -12 -4 l -12 -5 l -12 -4 l -11 -5 l -12 -5 l -12 -6 l -12 -7 l -13 -7 l -13 -8 l -14 -8 l -13 -9 l -13 -9 l -13 -10 l -12 -9 l -11 -9 l -10 -10 l -11 -10 l -10 -10 l -10 -11 l -11 -12 l -10 -12 l -10 -12 l -10 -13 l -9 -12 l -9 -11 l -8 -11 l -7 -10 l -6 -9 l -8 -11 l -7 -11 l -7 -11 l -7 -11 l -7 -12 l -6 -11 l -5 -11 l -6 -11 l -4 -10 l -4 -11 l -4 -11 l -4 -12 l -4 -13 l -4 -13 l -6 -28 l -3 -14 l -3 -12 l -1 -12 l -2 -11 l -1 -11 l -1 -11 l -1 -10 l 0 -34 l 1 -10 l 1 -11 l 2 -9 l 1 -10 l 2 -10 l 2 -11 l 3 -12 l 3 -12 l 3 -12 l 4 -13 l 4 -12 l 4 -12 l 4 -11 Z" />
+<path style="fill:rgb(0%,69%,0%);" d="M 2420 6449 l 12 -1 l 12 0 l 13 -1 l 14 -1 l 13 0 l 14 -1 l 50 0 l 12 -1 l 109 0 l 10 -1 l 21 0 l 11 -1 l 11 -1 l 11 -1 l 10 -1 l 9 -2 l 9 -2 l 9 -2 l 10 -4 l 10 -5 l 11 -5 l 11 -6 l 10 -6 l 11 -6 l 10 -5 l 11 -5 l 10 -5 l 11 -4 l 12 -5 l 13 -5 l 13 -4 l 12 -4 l 11 -4 l 11 -4 l 10 -4 l 10 -4 l 10 -4 l 10 -5 l 10 -4 l 9 -5 l 7 -4 l 8 -3 l 8 -5 l 8 -6 l 8 -6 l 6 -6 l 5 -8 l 4 -7 l 1 -7 l 1 -8 l 0 -19 l -1 -10 l -2 -9 l -2 -9 l -2 -8 l -3 -8 l -3 -9 l -3 -8 l -4 -9 l -4 -8 l -4 -9 l -4 -8 l -3 -8 l -4 -9 l -4 -10 l -4 -10 l -4 -11 l -3 -12 l -4 -10 l -3 -11 l -2 -9 l -4 -12 l -3 -13 l -2 -12 l -1 -11 l 0 -9 l 1 -6 l 1 -3 l 1 -2 l 3 -2 l 2 -2 l 4 0 l 3 -1 l 8 2 l 5 1 l 4 2 l 8 3 l 8 5 l 10 6 l 10 6 l 8 7 l 8 6 l 7 7 l 8 6 l 7 7 l 8 6 l 7 5 l 8 3 l 8 1 l 10 0 l 11 -1 l 11 -1 l 11 -2 l 11 -1 l 8 -1 l 9 -1 l 36 0 l 8 1 l 17 0 l 10 1 l 11 1 l 10 2 l 16 4 l 7 3 l 8 4 l 7 6 l 8 6 l 7 6 l 6 7 l 7 6 l 7 8 l 8 8 l 8 7 l 9 5 l 8 4 l 9 2 l 20 0 l 10 -2 l 9 -1 l 9 -1 l 8 -1 l 8 -1 l 9 1 l 7 2 l 7 2 l 5 4 l 5 5 l 4 6 l 5 8 l 4 9 l 3 9 l 3 9 l 2 7 l 4 16 l 2 9 l 2 8 l 2 9 l 1 7 l 1 8 l 1 9 l 1 9 l 2 8 l 1 6 l 2 3 l 2 0 l 2 -3 l 3 -6 l 4 -9 l 4 -11 l 4 -12 l 4 -11 l 3 -9 l 4 -9 l 3 -10 l 8 -20 l 4 -10 l 4 -9 l 4 -8 l 8 -18 l 5 -9 l 5 -8 l 5 -9 l 6 -8 l 5 -6 l 6 -6 l 5 -6 l 7 -5 l 7 -5 l 8 -5 l 9 -4 l 16 -6 l 8 -2 l 7 -2 l 9 -2 l 9 -1 l 18 -2 l 18 0 l 8 1 l 7 0 l 8 1 l 9 2 l 8 2 l 9 2 l 8 3 l 8 2 l 8 4 l 7 3 l 8 4 l 8 5 l 9 5 l 9 5 l 8 6 l 8 5 l 8 5 l 7 5 l 8 6 l 8 6 l 8 6 l 7 6 l 7 6 l 12 12 l 6 7 l 6 7 l 5 6 l 4 5 l 3 4 l 3 1 l 2 -2 l 2 -5 l 2 -7 l 3 -7 l 3 -7 l 3 -4 l 3 -3 l 4 -3 l 5 -3 l 6 -2 l 6 -2 l 7 -2 l 7 -1 l 8 -1 l 8 -1 l 10 0 l 11 -1 l 22 0 l 10 -1 l 21 0 l 11 -1 l 11 -1 l 12 -1 l 12 -1 l 11 -1 l 11 -2 l 20 -4 l 10 -3 l 11 -3 l 11 -3 l 11 -4 l 10 -3 l 10 -3 l 9 -3 l 8 -3 l 8 -3 l 9 -3 l 9 -4 l 9 -3 l 9 -3 l 8 -4 l 8 -3 l 8 -4 l 9 -3 l 9 -4 l 9 -3 l 9 -2 l 9 0 l 8 1 l 7 3 l 7 4 l 6 7 l 7 9 l 7 11 l 7 12 l 6 13 l 6 12 l 6 13 l 5 10 l 5 11 l 5 12 l 6 12 l 6 13 l 6 13 l 6 13 l 6 12 l 5 12 l 6 12 l 4 10 l 5 10 l 4 11 l 5 12 l 6 11 l 5 13 l 5 12 l 5 12 l 4 12 l 5 11 l 4 11 l 4 11 l 4 11 l 4 11 l 4 12 l 4 12 l 4 12 l 4 13 l 4 12 l 3 12 l 4 12 l 3 11 l 4 10 l 3 11 l 4 11 l 4 12 l 4 13 l 4 12 l 4 12 l 4 12 l 4 11 l 4 10 l 3 9 l 3 9 l 2 7 l 2 8 l 2 7 l 1 7 l 0 8 l -1 8 l -2 7 l -4 8 l -4 7 l -6 8 l -6 6 l -6 6 l -8 7 l -8 8 l -11 8 l -12 8 l -13 10 l -15 9 l -16 10 l -18 10 l -18 10 l -19 11 l -21 10 l -21 11 l -14 6 l -16 8 l -16 7 l -17 7 l -18 8 l -19 8 l -20 9 l -21 8 l -21 9 l -23 9 l -23 9 l -23 9 l -24 8 l -23 9 l -24 8 l -23 8 l -24 8 l -23 7 l -44 14 l -23 7 l -21 6 l -22 6 l -23 6 l -22 6 l -24 5 l -23 6 l -25 5 l -25 5 l -25 5 l -26 5 l -54 10 l -27 4 l -26 4 l -27 4 l -27 3 l -26 4 l -26 3 l -26 2 l -25 3 l -25 2 l -24 2 l -25 2 l -23 2 l -23 1 l -72 3 l -25 1 l -52 2 l -54 0 l -27 1 l -26 0 l -27 -1 l -53 0 l -50 -2 l -24 0 l -23 -1 l -22 -1 l -22 -2 l -21 -1 l -20 -1 l -19 -2 l -26 -2 l -25 -3 l -24 -3 l -25 -3 l -24 -3 l -24 -4 l -24 -5 l -24 -5 l -23 -5 l -22 -5 l -42 -12 l -19 -7 l -36 -14 l -16 -7 l -15 -7 l -15 -8 l -14 -8 l -14 -9 l -15 -9 l -14 -10 l -14 -11 l -14 -11 l -14 -12 l -14 -13 l -14 -13 l -14 -13 l -14 -14 l -13 -14 l -13 -13 l -12 -14 l -12 -14 l -12 -13 l -12 -14 l -11 -13 l -13 -16 l -13 -16 l -13 -17 l -14 -17 l -13 -17 l -13 -18 l -13 -18 l -12 -18 l -20 -34 l -8 -16 l -7 -15 l -4 -14 l -4 -13 l -1 -11 l 1 -11 l 2 -11 l 5 -10 l 7 -9 l 10 -9 l 11 -8 l 13 -7 l 15 -6 l 16 -6 l 16 -5 l 16 -4 l 16 -3 l 15 -3 l 15 -2 l 14 -2 l 15 -3 l 15 -2 l 15 -2 l 28 -4 l 14 -1 l 13 -2 l 12 -1 l 12 -1 l 11 -1 l 10 -1 Z" />
+<path style="fill:rgb(100%,84%,0%);" d="M 2452 4170 l -1 0 l -3 -3 l -9 -7 l -15 -11 l -19 -14 l -21 -17 l -22 -16 l -21 -16 l -19 -15 l -17 -12 l -15 -12 l -13 -10 l -12 -9 l -11 -8 l -12 -10 l -12 -10 l -12 -9 l -12 -10 l -11 -9 l -11 -9 l -10 -9 l -10 -8 l -9 -7 l -8 -7 l -7 -6 l -6 -6 l -9 -8 l -8 -7 l -7 -8 l -7 -6 l -5 -7 l -5 -5 l -3 -5 l -2 -5 l -1 -6 l 0 -5 l 2 -6 l 2 -6 l 4 -6 l 3 -6 l 4 -5 l 10 -14 l 5 -8 l 5 -9 l 4 -8 l 3 -6 l 6 -16 l 2 -8 l 3 -9 l 2 -8 l 2 -8 l 2 -7 l 1 -9 l 2 -9 l 1 -10 l 1 -11 l 1 -10 l 0 -38 l -1 -11 l 0 -11 l -1 -10 l -1 -11 l -1 -9 l -1 -10 l -2 -9 l -2 -11 l -3 -10 l -2 -11 l -3 -10 l -3 -10 l -3 -10 l -3 -9 l -3 -10 l -4 -11 l -5 -12 l -5 -11 l -5 -11 l -6 -10 l -7 -10 l -5 -8 l -7 -8 l -7 -8 l -24 -24 l -8 -7 l -8 -6 l -7 -5 l -7 -5 l -8 -5 l -16 -8 l -6 -3 l -6 -4 l -3 -4 l -1 -3 l 0 -5 l 3 -5 l 4 -6 l 5 -8 l 6 -8 l 5 -8 l 4 -9 l 1 -8 l -1 -7 l -3 -7 l -7 -7 l -10 -7 l -11 -7 l -13 -7 l -13 -6 l -13 -5 l -12 -5 l -11 -4 l -11 -5 l -10 -4 l -11 -4 l -10 -4 l -10 -5 l -9 -3 l -8 -4 l -8 -4 l -9 -4 l -9 -5 l -10 -5 l -10 -6 l -10 -5 l -10 -5 l -10 -4 l -8 -4 l -9 -4 l -9 -5 l -11 -4 l -10 -5 l -11 -5 l -11 -4 l -11 -5 l -10 -5 l -10 -4 l -12 -6 l -13 -6 l -13 -6 l -13 -5 l -11 -5 l -8 -2 l -7 -1 l -4 1 l -1 3 l 0 5 l 3 7 l 5 9 l 6 9 l 6 10 l 7 10 l 7 9 l 6 8 l 7 9 l 7 9 l 7 9 l 6 9 l 7 9 l 6 9 l 6 9 l 5 9 l 6 10 l 6 11 l 6 12 l 12 22 l 5 10 l 5 10 l 5 9 l 4 9 l 5 9 l 5 10 l 5 10 l 4 11 l 8 20 l 4 12 l 4 12 l 4 13 l 4 13 l 5 12 l 5 11 l 4 8 l 5 6 l 4 3 l 4 1 l 10 0 l 5 -2 l 6 -3 l 10 -8 l 5 -4 l 5 -4 l 9 -7 l 9 -7 l 9 -6 l 10 -5 l 9 -3 l 9 0 l 6 1 l 6 3 l 7 5 l 7 5 l 14 14 l 7 7 l 6 8 l 7 7 l 7 9 l 7 9 l 7 9 l 7 10 l 7 9 l 5 9 l 5 9 l 8 18 l 4 10 l 3 10 l 2 10 l 2 10 l 2 8 l 1 8 l 2 9 l 1 9 l 0 28 l -1 8 l -4 18 l -3 10 l -4 9 l -4 9 l -5 8 l -6 6 l -7 7 l -8 7 l -16 12 l -6 5 l -7 5 l -6 5 l -7 4 l -6 4 l -7 2 l -6 1 l -6 -2 l -7 -3 l -8 -4 l -8 -5 l -8 -6 l -7 -6 l -6 -5 l -7 -6 l -8 -6 l -7 -6 l -7 -6 l -6 -5 l -7 -5 l -7 -5 l -7 -6 l -16 -12 l -7 -5 l -5 -4 l -6 -5 l -7 -5 l -7 -6 l -7 -6 l -8 -5 l -7 -5 l -7 -5 l -7 -6 l -7 -5 l -8 -6 l -7 -7 l -6 -6 l -5 -7 l -3 -7 l -1 -7 l 0 -7 l 2 -8 l 4 -8 l 5 -9 l 5 -9 l 5 -8 l 5 -7 l 4 -6 l 2 -4 l 1 -3 l 2 -4 l 0 -7 l -1 -2 l -1 -2 l -4 -2 l -2 -2 l -2 -1 l -3 -1 l -4 -1 l -3 -1 l -4 -1 l -5 -1 l -8 -1 l -10 -1 l -11 -2 l -14 -2 l -15 -2 l -16 -3 l -18 -4 l -18 -5 l -19 -5 l -18 -6 l -19 -7 l -19 -8 l -17 -8 l -18 -9 l -18 -9 l -19 -11 l -19 -10 l -19 -11 l -19 -11 l -18 -10 l -16 -9 l -15 -7 l -13 -7 l -11 -4 l -9 -3 l -7 -1 l -6 1 l -3 3 l -2 5 l 0 7 l 2 9 l 3 10 l 4 12 l 5 12 l 7 14 l 6 13 l 7 14 l 7 14 l 8 13 l 7 14 l 7 15 l 8 15 l 8 15 l 8 16 l 8 15 l 8 16 l 7 15 l 7 14 l 6 14 l 5 12 l 5 11 l 4 11 l 6 14 l 4 15 l 4 14 l 4 13 l 3 12 l 2 10 l 3 9 l 4 14 l 2 5 l 3 6 l 6 8 l 3 3 l 6 2 l 5 0 l 5 -2 l 6 -4 l 7 -4 l 7 -6 l 7 -7 l 6 -5 l 13 -13 l 7 -6 l 8 -6 l 14 -8 l 7 -1 l 6 -1 l 14 4 l 8 5 l 8 5 l 8 6 l 8 6 l 16 14 l 9 7 l 10 8 l 11 9 l 10 9 l 10 8 l 9 8 l 9 7 l 8 6 l 8 7 l 7 8 l 8 7 l 7 8 l 7 8 l 5 7 l 6 8 l 4 8 l 4 9 l 4 9 l 3 11 l 2 10 l 1 9 l 0 9 l -2 8 l -3 8 l -5 7 l -6 8 l -9 8 l -11 7 l -12 7 l -13 7 l -15 7 l -9 4 l -10 4 l -11 4 l -12 4 l -13 4 l -13 4 l -15 4 l -15 3 l -16 3 l -16 2 l -15 1 l -16 1 l -32 0 l -16 -1 l -17 -2 l -17 -3 l -18 -4 l -19 -4 l -18 -4 l -18 -5 l -18 -6 l -16 -5 l -15 -6 l -13 -6 l -12 -5 l -9 -5 l -8 -5 l -5 -4 l -4 -3 l -3 -4 l -3 -3 l -2 -3 l -1 -4 l -1 -3 l 0 -6 l 1 -4 l 2 -3 l 1 -3 l 3 -3 l 2 -3 l 3 -2 l 3 -3 l 3 -2 l 3 -3 l 6 -4 l 8 -5 l 8 -6 l 8 -5 l 8 -6 l 7 -6 l 7 -6 l 5 -6 l 4 -5 l 2 -4 l 1 -5 l 1 -4 l 0 -10 l -2 -5 l -6 -10 l -5 -5 l -5 -4 l -7 -4 l -8 -4 l -9 -3 l -10 -4 l -12 -4 l -14 -4 l -15 -5 l -16 -5 l -18 -5 l -17 -6 l -18 -6 l -18 -7 l -17 -8 l -18 -8 l -30 -16 l -16 -10 l -16 -10 l -17 -10 l -16 -11 l -17 -11 l -15 -10 l -16 -10 l -14 -9 l -12 -8 l -12 -7 l -10 -6 l -9 -4 l -5 -2 l -12 -3 l -10 0 l -2 1 l -3 1 l -2 1 l -4 4 l -1 3 l -2 6 l 0 3 l -1 4 l 0 4 l 1 4 l 0 5 l 1 4 l 2 10 l 2 5 l 1 5 l 2 6 l 4 10 l 4 11 l 5 13 l 7 13 l 7 15 l 8 15 l 8 16 l 10 17 l 9 16 l 10 17 l 11 16 l 10 16 l 11 16 l 10 16 l 10 13 l 10 14 l 11 14 l 11 15 l 12 14 l 13 15 l 12 15 l 14 15 l 13 15 l 13 14 l 13 13 l 13 12 l 13 12 l 12 10 l 12 10 l 12 9 l 13 10 l 13 9 l 14 8 l 15 8 l 14 8 l 16 7 l 15 6 l 15 6 l 16 5 l 15 4 l 14 4 l 15 4 l 14 3 l 14 3 l 13 2 l 15 2 l 15 3 l 15 2 l 16 2 l 17 1 l 32 2 l 16 1 l 31 0 l 14 -1 l 13 -1 l 13 -1 l 14 -2 l 15 -3 l 14 -3 l 15 -4 l 15 -5 l 14 -5 l 14 -5 l 14 -6 l 13 -6 l 12 -5 l 12 -6 l 11 -5 l 13 -6 l 13 -7 l 13 -7 l 14 -7 l 13 -7 l 13 -7 l 11 -7 l 11 -6 l 9 -5 l 7 -5 l 7 -4 l 7 -5 l 6 -4 l 6 -3 l 6 -3 l 6 -1 l 5 -1 l 6 0 l 6 1 l 14 6 l 9 5 l 9 7 l 11 7 l 12 9 l 12 9 l 12 10 l 12 10 l 12 11 l 12 10 l 10 9 l 11 9 l 11 10 l 11 10 l 12 10 l 12 11 l 12 10 l 12 11 l 11 10 l 11 9 l 10 9 l 10 8 l 10 8 l 10 8 l 10 9 l 12 9 l 13 10 l 14 10 l 15 12 l 13 10 l 12 9 l 7 5 l 3 3 l 1 0" />
+<path d="M 2876 5202 l 1 1 l 3 4 l 7 10 l 10 14 l 11 15 l 11 13 l 9 12 l 8 10 l 7 8 l 6 7 l 8 8 l 8 8 l 9 8 l 9 7 l 10 7 l 9 7 l 9 6 l 9 5 l 9 6 l 10 6 l 11 6 l 12 7 l 11 6 l 11 6 l 10 4 l 10 5 l 9 3 l 9 4 l 10 3 l 9 3 l 10 2 l 8 2 l 9 2 l 7 2 l 8 2 l 8 2 l 8 1 l 9 2 l 9 2 l 9 2 l 8 1 l 8 1 l 8 1 l 9 1 l 9 1 l 9 1 l 17 0 l 8 1 l 15 0 l 8 -1 l 10 0 l 10 -1 l 6 -1 l 1 0" />
+<path d="M 3161 5427 l 1 0 l 4 3 l 10 6 l 16 10 l 19 11 l 20 12 l 18 11 l 17 9 l 14 8 l 13 7 l 10 5 l 11 5 l 22 10 l 11 4 l 12 4 l 11 3 l 11 3 l 11 2 l 10 3 l 10 1 l 10 2 l 10 2 l 10 2 l 12 1 l 12 2 l 12 1 l 13 2 l 12 0 l 11 1 l 22 0 l 10 -1 l 10 -1 l 10 -2 l 11 -2 l 11 -2 l 22 -6 l 10 -3 l 10 -3 l 10 -3 l 10 -3 l 11 -3 l 11 -3 l 11 -4 l 12 -3 l 12 -4 l 12 -3 l 12 -4 l 10 -3 l 11 -3 l 10 -4 l 11 -3 l 11 -4 l 12 -3 l 12 -4 l 12 -4 l 13 -3 l 12 -3 l 11 -3 l 12 -2 l 11 -3 l 13 -2 l 13 -2 l 14 -2 l 15 -2 l 15 -2 l 14 -2 l 14 -1 l 13 -2 l 12 -1 l 13 -1 l 12 -2 l 14 -2 l 14 -2 l 14 -2 l 14 -2 l 14 -3 l 14 -4 l 14 -3 l 13 -4 l 22 -8 l 13 -4 l 13 -5 l 13 -6 l 14 -5 l 13 -6 l 13 -6 l 13 -6 l 13 -5 l 11 -6 l 12 -5 l 13 -6 l 13 -6 l 14 -6 l 14 -6 l 14 -6 l 14 -6 l 13 -6 l 12 -5 l 12 -5 l 11 -5 l 11 -5 l 12 -4 l 11 -5 l 12 -5 l 12 -6 l 11 -5 l 11 -5 l 10 -5 l 9 -5 l 8 -4 l 10 -7 l 10 -7 l 9 -7 l 10 -8 l 9 -9 l 9 -9 l 8 -9 l 7 -9 l 6 -8 l 6 -9 l 7 -10 l 8 -12 l 9 -15 l 10 -15 l 8 -14 l 7 -10 l 3 -4 l 0 -1" />
+<path style="fill:rgb(82%,0%,0%);" d="M 2640 4897 l 3 5 l 4 5 l 5 5 l 4 5 l 5 4 l 5 4 l 12 6 l 7 3 l 7 2 l 7 2 l 7 1 l 7 1 l 16 2 l 7 1 l 7 1 l 7 0 l 6 1 l 7 1 l 7 1 l 6 0 l 5 1 l 5 -1 l 6 0 l 6 -1 l 7 -1 l 8 -2 l 8 -1 l 7 -2 l 8 -1 l 8 -2 l 10 -2 l 10 -2 l 9 -3 l 8 -2 l 8 -3 l 10 -4 l 9 -5 l 10 -5 l 16 -12 l 6 -5 l 6 -5 l 6 -6 l 6 -7 l 6 -6 l 5 -7 l 5 -7 l 6 -7 l 6 -8 l 6 -9 l 7 -10 l 6 -9 l 7 -8 l 6 -9 l 6 -9 l 7 -9 l 7 -8 l 6 -8 l 11 -11 l 4 -6 l 5 -5 l 4 -4 l 3 -5 l 3 -4 l 2 -5 l 1 -7 l 0 -14 l -2 -12 l -2 -7 l -2 -8 l -2 -7 l -3 -6 l -2 -5 l -2 -6 l -3 -6 l -3 -5 l -2 -6 l -6 -10 l -4 -6 l -3 -6 l -4 -6 l -8 -12 l -1 -2 l -2 -2 l -2 -2 l -4 -4 l -3 -1 l -4 -1 l -5 0 l -5 1 l -12 4 l -8 3 l -8 4 l -9 5 l -10 7 l -11 7 l -11 7 l -11 8 l -13 10 l -14 10 l -15 11 l -15 12 l -16 13 l -17 14 l -17 13 l -16 14 l -17 14 l -16 13 l -15 13 l -14 12 l -13 12 l -12 11 l -11 10 l -10 9 l -13 12 l -11 11 l -17 19 l -5 8 l -5 7 l -2 5 l -2 5 l 0 7 l 1 3 Z7" />
+<path d="M 2891 5190 l 2 1 l 9 3 l 13 4 l 13 5 l 10 3 l 9 3 l 8 3 l 9 3 l 10 3 l 9 3 l 9 3 l 9 2 l 8 2 l 9 2 l 10 1 l 9 1 l 9 2 l 8 1 l 8 0 l 8 1 l 8 1 l 8 0 l 8 1 l 7 0 l 7 1 l 68 0 l 4 -1 l 4 0 l 1 -1 l 1 0 l 0 -1 l 1 0 l 0 -1" />
+<path style="fill:rgb(100%,100%,100%);" d="M 2468 6609 l -6 -7 l -6 -7 l -8 -7 l -8 -7 l -8 -8 l -9 -7 l -8 -7 l -7 -6 l -8 -6 l -9 -7 l -9 -6 l -9 -7 l -10 -6 l -10 -6 l -9 -5 l -9 -4 l -10 -5 l -11 -4 l -11 -3 l -13 -4 l -12 -3 l -13 -3 l -12 -2 l -11 -2 l -10 -1 l -10 -1 l -10 -2 l -11 0 l -11 -1 l -12 -1 l -23 0 l -11 -1 l -10 1 l -23 0 l -13 1 l -13 0 l -14 1 l -13 1 l -14 2 l -13 1 l -13 2 l -12 2 l -10 1 l -11 2 l -11 2 l -11 2 l -12 2 l -13 3 l -12 3 l -13 3 l -26 6 l -12 3 l -13 4 l -11 2 l -12 4 l -13 3 l -13 3 l -28 8 l -15 5 l -15 4 l -15 5 l -14 4 l -15 5 l -14 5 l -13 4 l -13 5 l -15 6 l -16 6 l -16 6 l -16 6 l -16 7 l -17 8 l -15 7 l -15 7 l -14 6 l -12 6 l -11 6 l -10 6 l -14 8 l -12 8 l -11 8 l -11 9 l -8 8 l -7 7 l -6 7 l -5 6 l -6 8 l -5 9 l -4 10 l -3 10 l -2 10 l -1 10 l 0 16 l 1 10 l 2 10 l 2 10 l 2 11 l 2 9 l 3 10 l 6 18 l 4 10 l 5 10 l 5 10 l 6 10 l 5 9 l 7 8 l 6 7 l 8 8 l 9 8 l 10 8 l 10 7 l 11 7 l 11 6 l 11 6 l 9 4 l 10 5 l 10 4 l 12 4 l 12 4 l 12 4 l 12 4 l 12 3 l 12 3 l 12 3 l 12 2 l 13 2 l 13 2 l 15 2 l 15 1 l 16 2 l 15 1 l 15 1 l 14 1 l 15 1 l 11 0 l 13 1 l 13 0 l 13 1 l 28 0 l 14 1 l 27 0 l 12 1 l 12 0 l 11 1 l 26 0 l 14 1 l 13 0 l 14 1 l 14 0 l 12 1 l 12 0 l 12 1 l 32 0 l 11 1 l 101 0 l 9 -1 l 10 -1 l 10 -1 l 11 -2 l 22 -8 l 11 -5 l 11 -7 l 11 -7 l 11 -9 l 11 -10 l 11 -11 l 9 -12 l 10 -13 l 10 -14 l 10 -15 l 10 -17 l 11 -18 l 10 -19 l 10 -19 l 10 -19 l 10 -19 l 9 -18 l 8 -18 l 7 -16 l 6 -16 l 6 -14 l 5 -12 l 5 -16 l 4 -14 l 3 -13 l 2 -11 l 0 -20 l -1 -8 l -2 -7 l -2 -6 l -3 -5 l -3 -4 Z" />
+<path d="M 4102 4658 l -2 1 l -8 6 l -12 8 l -12 8 l -9 5 l -8 4 l -7 3 l -8 3 l -18 4 l -9 1 l -8 1 l -7 1 l -8 0 l -8 1 l -9 0 l -9 1 l -16 0 l -8 1 l -29 0 l -10 -1 l -9 -1 l -8 -1 l -9 -2 l -10 -2 l -22 -6 l -10 -3 l -10 -4 l -8 -3 l -9 -3 l -9 -4 l -10 -4 l -10 -4 l -9 -5 l -9 -5 l -9 -4 l -9 -6 l -9 -6 l -9 -6 l -10 -7 l -10 -7 l -9 -7 l -8 -6 l -8 -6 l -7 -6 l -8 -6 l -8 -6 l -8 -6 l -8 -6 l -8 -6 l -8 -5 l -8 -5 l -8 -5 l -9 -5 l -9 -6 l -10 -5 l -11 -6 l -10 -5 l -10 -4 l -9 -5 l -10 -4 l -10 -5 l -11 -4 l -12 -4 l -12 -5 l -12 -4 l -12 -3 l -11 -3 l -10 -3 l -10 -2 l -11 -2 l -11 -2 l -12 -2 l -12 -2 l -12 -2 l -11 -1 l -11 -2 l -10 -1 l -10 -1 l -11 0 l -11 -1 l -11 -1 l -44 0 l -10 1 l -9 0 l -12 2 l -13 1 l -12 2 l -13 3 l -12 3 l -11 2 l -10 3 l -9 3 l -8 3 l -7 4 l -8 4 l -8 4 l -7 5 l -8 4 l -8 5 l -8 6 l -7 4 l -8 5 l -10 6 l -11 7 l -14 8 l -15 9 l -14 9 l -10 6 l -4 3 l -1 0" />
+<path d="M 2940 2986 l -1 -1 l -7 -4 l -12 -8 l -15 -10 l -14 -9 l -12 -7 l -10 -6 l -10 -4 l -10 -4 l -10 -3 l -12 -3 l -11 -3 l -12 -2 l -12 -2 l -11 -1 l -11 -1 l -10 0 l -12 -1 l -12 1 l -12 0 l -12 1 l -12 2 l -11 2 l -10 2 l -10 3 l -10 4 l -11 4 l -11 5 l -10 5 l -10 6 l -9 5 l -7 6 l -8 6 l -7 7 l -7 7 l -7 8 l -6 8 l -6 9 l -4 8 l -4 8 l -4 9 l -3 9 l -3 11 l -2 10 l -2 11 l -2 11 l -1 10 l -1 10 l 0 40 l 2 11 l 1 10 l 3 9 l 2 9 l 4 9 l 4 9 l 5 10 l 5 10 l 7 9 l 6 9 l 6 8 l 7 7 l 6 7 l 7 6 l 8 7 l 9 6 l 8 7 l 8 5 l 8 5 l 8 5 l 8 4 l 8 4 l 9 4 l 10 4 l 10 4 l 9 3 l 10 3 l 9 2 l 9 2 l 10 2 l 10 1 l 12 2 l 11 1 l 10 1 l 11 0 l 9 1 l 19 0 l 10 1 l 10 0 l 10 -1 l 19 0 l 9 -1 l 9 -1 l 9 0 l 9 -2 l 10 -1 l 18 -2 l 9 -2 l 7 -1 l 10 -2 l 9 -1 l 10 -2 l 9 -2 l 8 -1 l 8 0 l 7 -1 l 7 0 l 14 2 l 7 2 l 7 3 l 14 7 l 9 4 l 9 4 l 9 4 l 9 2 l 10 2 l 10 1 l 12 -1 l 11 0 l 10 -1 l 9 -2 l 8 -1 l 8 -2 l 7 -3 l 6 -3 l 5 -4 l 4 -5 l 3 -6 l 3 -8 l 2 -9 l 1 -10 l 0 -20 l -1 -10 l -1 -11 l -3 -11 l -3 -11 l -3 -10 l -4 -8 l -4 -7 l -6 -7 l -8 -8 l -9 -8 l -6 -5 l -1 -1" />
+<path style="fill:rgb(100%,100%,100%);" d="M 3309 2031 l 9 -14 l 10 -13 l 10 -12 l 11 -13 l 11 -12 l 11 -12 l 11 -12 l 12 -11 l 11 -10 l 12 -9 l 11 -9 l 12 -9 l 12 -9 l 14 -8 l 14 -9 l 15 -8 l 16 -8 l 17 -8 l 16 -6 l 17 -5 l 16 -4 l 15 -2 l 15 0 l 14 1 l 11 2 l 12 4 l 12 4 l 12 6 l 11 8 l 12 8 l 11 10 l 11 11 l 10 11 l 10 11 l 8 12 l 8 12 l 7 12 l 6 12 l 5 13 l 5 13 l 5 13 l 4 15 l 4 15 l 3 16 l 3 17 l 4 34 l 2 18 l 1 17 l 0 17 l 1 17 l 0 48 l -1 17 l 0 17 l -1 19 l -2 38 l -2 20 l -1 20 l -2 20 l -3 20 l -4 38 l -3 19 l -6 36 l -4 17 l -3 18 l -4 18 l -5 19 l -5 19 l -5 20 l -5 19 l -6 20 l -6 19 l -7 19 l -6 19 l -7 17 l -6 17 l -7 16 l -6 15 l -7 15 l -8 17 l -8 16 l -8 16 l -10 16 l -10 16 l -10 16 l -11 16 l -11 15 l -12 15 l -11 13 l -12 13 l -12 11 l -11 11 l -12 10 l -12 10 l -13 9 l -14 9 l -14 8 l -15 8 l -16 8 l -16 7 l -17 6 l -17 5 l -16 4 l -16 3 l -15 2 l -15 1 l -15 1 l -15 -1 l -15 -1 l -15 -3 l -16 -3 l -16 -5 l -16 -6 l -16 -6 l -15 -8 l -15 -8 l -14 -9 l -13 -9 l -12 -10 l -11 -11 l -10 -10 l -9 -12 l -9 -12 l -8 -13 l -8 -15 l -8 -15 l -7 -16 l -6 -16 l -6 -17 l -5 -16 l -4 -17 l -4 -15 l -3 -16 l -3 -14 l -2 -14 l -2 -14 l -1 -14 l -1 -15 l -1 -14 l 0 -31 l 1 -16 l 1 -16 l 2 -16 l 2 -16 l 3 -16 l 4 -15 l 3 -15 l 4 -16 l 4 -14 l 5 -14 l 5 -15 l 5 -16 l 7 -16 l 6 -18 l 7 -17 l 8 -18 l 7 -19 l 8 -18 l 8 -17 l 8 -18 l 8 -17 l 8 -16 l 8 -16 l 8 -15 l 8 -15 l 8 -16 l 8 -15 l 8 -16 l 9 -16 l 9 -16 l 10 -16 l 9 -16 l 9 -16 l 10 -15 l 9 -14 l 8 -14 l 9 -12 l 8 -12 l 7 -12 Z" />
+<path style="stroke-width:45;" d="M 2498 3459 l 19 0 l 15 1 l 13 1 l 10 0 l 8 1 l 8 2 l 8 3 l 8 4 l 8 5 l 8 5 l 7 7 l 7 7 l 12 12 l 7 7 l 7 8 l 8 8 l 7 8 l 7 8 l 14 14 l 7 8 l 7 8 l 8 8 l 7 8 l 8 7 l 7 7 l 7 7 l 7 7 l 7 7 l 8 7 l 9 8 l 8 7 l 8 8 l 8 7 l 7 8 l 32 32 l 9 9 l 8 9 l 9 8 l 9 7 l 7 6 l 8 6 l 9 7 l 9 6 l 10 7 l 9 6 l 10 6 l 10 6 l 9 6 l 10 5 l 9 5 l 10 6 l 10 5 l 11 6 l 11 6 l 11 5 l 12 5 l 11 5 l 10 4 l 11 4 l 10 4 l 11 3 l 12 3 l 12 3 l 13 3 l 13 3 l 14 2 l 13 2 l 12 2 l 13 2 l 10 1 l 12 1 l 11 1 l 13 0 l 13 1 l 13 0 l 13 1 l 37 0 l 11 -1 l 11 0 l 13 -1 l 13 -1 l 13 -2 l 14 -1 l 14 -3 l 14 -2 l 13 -3 l 13 -3 l 12 -4 l 12 -3 l 12 -5 l 12 -4 l 13 -5 l 13 -6 l 14 -6 l 13 -6 l 13 -7 l 12 -5 l 12 -6 l 11 -5 l 11 -6 l 11 -5 l 11 -6 l 12 -5 l 12 -6 l 11 -6 l 12 -6 l 11 -6 l 11 -6 l 11 -6 l 11 -6 l 12 -7 l 12 -7 l 12 -7 l 12 -8 l 13 -8 l 11 -8 l 10 -7 l 10 -6 l 8 -7 l 9 -7 l 9 -8 l 8 -8 l 8 -7 l 7 -6 l 8 -6 l 7 -5 l 7 -4 l 7 -3 l 8 -2 l 10 -3 l 10 -1 l 9 -1 l 10 -1 l 8 -1 l 17 0 l 9 -1 l 29 0" />
+<path style="fill:rgb(100%,100%,100%);" d="M 2870 2736 l 6 -9 l 6 -8 l 6 -9 l 7 -9 l 6 -11 l 6 -11 l 6 -12 l 6 -13 l 6 -14 l 6 -15 l 4 -13 l 5 -13 l 5 -14 l 5 -16 l 6 -17 l 6 -18 l 5 -19 l 12 -38 l 6 -18 l 6 -19 l 10 -34 l 5 -16 l 5 -16 l 5 -15 l 5 -16 l 10 -32 l 5 -16 l 5 -16 l 5 -15 l 5 -15 l 5 -14 l 5 -13 l 4 -12 l 8 -22 l 5 -13 l 5 -12 l 5 -12 l 4 -12 l 5 -12 l 5 -13 l 5 -12 l 5 -11 l 5 -11 l 4 -10 l 4 -10 l 4 -9 l 4 -12 l 5 -11 l 4 -12 l 5 -13 l 5 -12 l 4 -12 l 4 -11 l 4 -11 l 6 -18 l 3 -10 l 3 -10 l 3 -10 l 2 -20 l -1 -10 l -1 -10 l -3 -10 l -3 -8 l -3 -7 l -4 -8 l -5 -9 l -6 -8 l -6 -8 l -8 -8 l -8 -7 l -8 -6 l -9 -5 l -9 -3 l -9 -2 l -10 -2 l -11 0 l -11 2 l -13 2 l -13 3 l -13 4 l -13 5 l -13 6 l -12 5 l -11 6 l -11 5 l -9 6 l -11 7 l -11 7 l -10 7 l -10 8 l -10 9 l -10 10 l -10 10 l -10 11 l -10 11 l -10 13 l -8 9 l -8 10 l -9 12 l -9 12 l -10 13 l -11 15 l -11 14 l -10 16 l -11 15 l -11 16 l -10 15 l -10 15 l -9 15 l -9 15 l -9 15 l -9 15 l -9 16 l -9 16 l -9 16 l -9 17 l -8 17 l -8 16 l -8 16 l -7 14 l -7 14 l -6 13 l -6 12 l -5 11 l -6 12 l -5 12 l -5 11 l -4 11 l -5 12 l -4 12 l -4 11 l -3 12 l -3 13 l -3 12 l -3 13 l -2 14 l -2 12 l -2 14 l -2 14 l -1 16 l -2 17 l -1 18 l -1 17 l -1 18 l -1 18 l 0 17 l 1 16 l 0 15 l 1 14 l 2 14 l 3 17 l 4 16 l 5 15 l 6 14 l 6 14 l 7 12 l 7 11 l 7 9 l 7 8 l 7 7 l 8 7 l 8 7 l 9 7 l 9 5 l 10 5 l 9 4 l 10 3 l 9 2 l 10 2 l 24 0 l 13 -1 l 14 -3 l 13 -3 l 12 -6 l 11 -6 l 9 -6 l 10 -7 l 9 -9 l 10 -9 l 9 -10 l 9 -11 l 9 -10 l 8 -10 l 7 -10 Z" />
+<path d="M 3489 1649 l 1 0 l 4 -3 l 10 -6 l 16 -8 l 19 -10 l 20 -11 l 19 -10 l 18 -8 l 16 -7 l 14 -5 l 13 -4 l 13 -4 l 13 -2 l 13 -2 l 14 -1 l 29 0 l 15 1 l 30 4 l 14 3 l 13 4 l 12 4 l 12 4 l 12 5 l 11 6 l 12 6 l 11 7 l 12 9 l 11 9 l 11 10 l 10 10 l 10 11 l 8 11 l 8 12 l 7 12 l 6 11 l 6 12 l 5 14 l 5 15 l 6 17 l 6 20 l 6 22 l 6 23 l 6 22 l 6 21 l 4 15 l 2 9 l 1 4 l 0 1" />
+<path d="M 3278 1680 l 0 -1 l -1 -5 l -3 -10 l -4 -14 l -5 -16 l -5 -14 l -4 -13 l -10 -18 l -5 -6 l -7 -7 l -7 -5 l -8 -5 l -10 -5 l -10 -4 l -11 -4 l -11 -3 l -12 -2 l -11 -2 l -11 -1 l -11 -1 l -12 -1 l -13 0 l -14 1 l -14 1 l -15 2 l -14 3 l -13 4 l -13 4 l -13 5 l -20 12 l -11 7 l -11 8 l -12 9 l -12 10 l -12 11 l -13 11 l -12 12 l -12 11 l -11 12 l -12 12 l -9 10 l -10 9 l -10 11 l -10 11 l -11 11 l -11 12 l -11 13 l -12 13 l -11 14 l -12 13 l -11 14 l -11 14 l -10 13 l -10 13 l -10 13 l -9 14 l -9 13 l -9 14 l -9 14 l -9 15 l -9 16 l -9 16 l -9 16 l -9 17 l -9 17 l -8 16 l -8 16 l -7 16 l -7 15 l -6 15 l -6 14 l -6 13 l -6 15 l -6 16 l -6 15 l -5 16 l -12 32 l -5 16 l -5 15 l -5 16 l -5 14 l -4 14 l -5 13 l -4 12 l -4 12 l -5 13 l -4 14 l -6 14 l -5 14 l -5 14 l -6 15 l -6 14 l -5 14 l -6 14 l -5 13 l -5 13 l -5 13 l -4 13 l -5 14 l -6 15 l -6 17 l -7 19 l -7 22 l -8 23 l -7 22 l -6 17 l -4 12 l -2 5 l 0 1" />
+<path style="fill:rgb(100%,84%,0%);" d="M 4036 5613 l 12 8 l 12 8 l 11 8 l 12 7 l 12 8 l 11 7 l 11 7 l 11 7 l 10 6 l 9 6 l 10 6 l 8 5 l 22 14 l 11 7 l 12 7 l 11 8 l 12 7 l 12 8 l 10 7 l 10 6 l 10 7 l 9 6 l 10 6 l 10 6 l 10 7 l 9 6 l 10 7 l 9 5 l 8 6 l 7 4 l 6 4 l 10 7 l 9 5 l 9 5 l 8 4 l 7 3 l 6 2 l 7 1 l 14 0 l 7 -1 l 6 -2 l 5 -2 l 6 -2 l 5 -4 l 5 -3 l 4 -3 l 8 -8 l 3 -5 l 4 -5 l 4 -5 l 3 -5 l 8 -10 l 5 -6 l 3 -5 l 3 -5 l 4 -6 l 3 -7 l 2 -7 l 2 -7 l 1 -6 l 0 -13 l -1 -7 l -1 -8 l -1 -6 l -1 -6 l -2 -5 l -3 -5 l -3 -6 l -4 -5 l -9 -9 l -5 -4 l -5 -5 l -7 -5 l -7 -5 l -7 -5 l -7 -5 l -7 -5 l -8 -5 l -9 -6 l -20 -12 l -9 -6 l -8 -5 l -9 -5 l -9 -6 l -11 -7 l -10 -7 l -10 -6 l -10 -7 l -9 -6 l -10 -6 l -9 -6 l -10 -7 l -11 -6 l -9 -6 l -9 -6 l -8 -5 l -8 -4 l -6 -4 l -7 -4 l -7 -4 l -7 -4 l -14 -8 l -7 -4 l -7 -5 l -8 -6 l -9 -6 l -9 -6 l -10 -8 l -9 -7 l -9 -6 l -7 -5 l -6 -5 l -5 -3 l -4 -3 l -3 -2 l -4 -1 l -14 0 l -6 1 l -7 1 l -8 1 l -9 2 l -10 1 l -12 2 l -12 2 l -13 2 l -12 1 l -12 2 l -12 2 l -12 2 l -12 2 l -12 1 l -13 2 l -12 3 l -12 2 l -10 2 l -10 1 l -8 2 l -7 2 l -3 1 l -2 0 l -6 3 l -2 0 l -1 1 l -2 1 l -2 2 l 0 2 l -1 1 l 0 4 l 4 8 l 2 2 l 4 4 l 2 3 l 3 2 l 6 6 l 7 6 l 10 7 l 10 9 l 12 9 l 13 10 l 15 10 l 14 11 l 15 10 l 14 10 l 14 10 l 13 9 Z" />
+<path style="fill:rgb(82%,0%,0%);" d="M 2303 4762 l 6 8 l 7 7 l 7 7 l 7 8 l 7 7 l 7 6 l 6 6 l 6 5 l 8 7 l 8 7 l 9 7 l 9 6 l 9 5 l 9 4 l 7 2 l 8 3 l 9 2 l 9 2 l 10 2 l 10 1 l 10 2 l 9 1 l 9 0 l 11 1 l 10 1 l 44 0 l 9 -1 l 9 -1 l 10 -1 l 10 -1 l 10 -2 l 11 -2 l 20 -4 l 9 -2 l 9 -2 l 10 -3 l 11 -2 l 10 -3 l 11 -3 l 10 -3 l 9 -3 l 8 -3 l 8 -2 l 8 -4 l 8 -3 l 7 -4 l 8 -4 l 7 -4 l 7 -5 l 12 -10 l 7 -6 l 7 -7 l 8 -7 l 8 -8 l 8 -9 l 7 -8 l 8 -8 l 6 -7 l 14 -14 l 7 -8 l 8 -9 l 7 -8 l 8 -8 l 7 -8 l 6 -8 l 7 -7 l 7 -9 l 16 -18 l 8 -10 l 8 -9 l 6 -9 l 7 -8 l 5 -7 l 5 -8 l 5 -7 l 4 -8 l 5 -8 l 3 -8 l 3 -7 l 3 -7 l 1 -7 l 2 -7 l 0 -8 l 1 -8 l 0 -17 l -1 -9 l 0 -8 l -2 -16 l -1 -9 l -2 -9 l -2 -9 l -2 -10 l -3 -9 l -3 -8 l -4 -7 l -5 -8 l -5 -7 l -6 -7 l -7 -8 l -7 -6 l -8 -7 l -7 -6 l -6 -5 l -7 -5 l -7 -4 l -8 -5 l -8 -5 l -8 -4 l -7 -4 l -8 -4 l -7 -3 l -7 -4 l -16 -6 l -9 -3 l -9 -2 l -8 -3 l -8 -2 l -16 -2 l -8 -1 l -9 -1 l -26 0 l -8 1 l -8 1 l -10 1 l -10 2 l -10 2 l -11 4 l -9 3 l -8 4 l -4 3 l -5 3 l -6 5 l -7 6 l -9 7 l -10 9 l -12 11 l -14 13 l -16 14 l -18 17 l -11 10 l -12 11 l -14 12 l -14 13 l -15 14 l -16 15 l -16 15 l -17 16 l -17 16 l -17 16 l -16 17 l -16 15 l -14 15 l -14 15 l -13 13 l -11 13 l -11 12 l -9 11 l -8 12 l -8 10 l -6 11 l -5 9 l -4 10 l -3 8 l -1 8 l -1 8 l 0 7 l 1 6 l 2 6 l 2 5 l 3 4 l 3 5 l 3 4 Z" />
+<path style="fill:rgb(100%,100%,100%);" d="M 2288 6848 l 4 -11 l 6 -10 l 7 -12 l 8 -11 l 9 -11 l 10 -10 l 10 -10 l 9 -9 l 9 -7 l 9 -7 l 9 -7 l 8 -5 l 9 -6 l 8 -6 l 10 -5 l 9 -5 l 8 -5 l 9 -4 l 9 -4 l 8 -4 l 9 -5 l 9 -5 l 10 -5 l 11 -5 l 11 -5 l 12 -6 l 11 -5 l 11 -5 l 10 -5 l 10 -4 l 10 -4 l 10 -4 l 11 -4 l 11 -4 l 12 -4 l 12 -3 l 11 -4 l 11 -3 l 11 -3 l 11 -2 l 11 -3 l 11 -3 l 13 -2 l 13 -3 l 13 -2 l 13 -3 l 13 -2 l 13 -2 l 12 -2 l 12 -1 l 11 -2 l 12 -1 l 12 -2 l 13 -1 l 13 -1 l 13 -1 l 12 0 l 12 -1 l 22 0 l 11 -1 l 11 1 l 24 0 l 12 1 l 13 1 l 12 1 l 11 1 l 12 1 l 11 2 l 10 1 l 12 2 l 12 2 l 12 3 l 13 2 l 12 3 l 12 3 l 12 2 l 10 3 l 10 3 l 12 4 l 12 3 l 12 5 l 13 4 l 12 5 l 11 5 l 10 5 l 10 6 l 10 5 l 10 6 l 10 7 l 11 8 l 11 8 l 10 8 l 9 8 l 9 9 l 7 6 l 7 7 l 7 8 l 7 8 l 7 8 l 7 9 l 7 8 l 6 9 l 5 8 l 5 8 l 6 9 l 5 11 l 5 12 l 5 12 l 5 12 l 4 12 l 3 12 l 4 11 l 2 9 l 4 20 l 2 11 l 2 11 l 2 10 l 1 11 l 2 9 l 1 10 l 1 8 l 0 15 l -1 5 l -1 6 l -2 5 l -2 5 l -4 6 l -10 10 l -7 6 l -8 5 l -9 5 l -11 4 l -11 5 l -13 5 l -12 4 l -13 4 l -14 4 l -32 8 l -19 4 l -20 4 l -21 3 l -22 4 l -23 3 l -25 3 l -24 3 l -52 4 l -25 1 l -26 0 l -26 1 l -78 -3 l -24 -2 l -50 -6 l -26 -3 l -26 -4 l -27 -4 l -27 -5 l -56 -12 l -28 -6 l -28 -6 l -27 -7 l -26 -7 l -25 -7 l -25 -7 l -23 -7 l -22 -7 l -20 -7 l -19 -7 l -18 -7 l -16 -6 l -15 -7 l -17 -7 l -15 -8 l -14 -8 l -13 -8 l -11 -8 l -10 -8 l -9 -8 l -7 -8 l -6 -8 l -5 -8 l -3 -8 l -3 -8 l -1 -7 l -1 -7 l 0 -7 l 1 -6 l 2 -7 Z" />
+<path style="fill:rgb(82%,0%,0%);" d="M 2232 4239 l -8 3 l -8 5 l -9 4 l -9 5 l -8 5 l -7 6 l -7 5 l -7 6 l -7 8 l -8 8 l -7 9 l -7 10 l -5 7 l -5 9 l -5 9 l -6 11 l -5 10 l -4 10 l -4 10 l -2 8 l -3 9 l -2 9 l -1 9 l -2 18 l 0 17 l -1 9 l 0 47 l 1 9 l 0 9 l 2 9 l 1 8 l 3 8 l 3 9 l 4 9 l 5 9 l 5 8 l 6 8 l 6 8 l 7 7 l 9 8 l 9 8 l 10 8 l 10 8 l 10 7 l 10 6 l 8 5 l 9 5 l 9 4 l 9 3 l 9 3 l 10 3 l 10 2 l 9 1 l 10 2 l 10 1 l 11 1 l 12 2 l 26 2 l 13 1 l 11 0 l 11 1 l 11 1 l 46 0 l 12 -2 l 10 -1 l 11 -2 l 18 -6 l 9 -3 l 10 -4 l 10 -5 l 11 -5 l 9 -5 l 10 -5 l 8 -6 l 9 -5 l 10 -7 l 20 -16 l 10 -9 l 9 -9 l 8 -9 l 6 -8 l 6 -8 l 5 -8 l 4 -7 l 4 -8 l 3 -9 l 3 -8 l 2 -7 l 1 -7 l 2 -7 l 1 -8 l 2 -10 l 1 -10 l 0 -22 l -1 -11 l -2 -9 l -2 -10 l -2 -11 l -3 -11 l -3 -12 l -4 -11 l -4 -10 l -3 -9 l -4 -9 l -5 -8 l -5 -9 l -6 -8 l -6 -8 l -7 -7 l -6 -7 l -7 -6 l -7 -5 l -6 -5 l -8 -5 l -9 -5 l -10 -5 l -11 -5 l -12 -5 l -12 -5 l -13 -4 l -13 -5 l -12 -3 l -13 -4 l -14 -3 l -15 -3 l -16 -4 l -16 -3 l -16 -3 l -16 -2 l -28 -4 l -12 -1 l -11 -1 l -15 -1 l -13 0 l -12 1 l -11 2 l -10 2 l -8 3 l -7 3 Z" />
+<path style="fill:rgb(82%,0%,0%);" d="M 2246 4048 l 1 -8 l 1 -10 l 3 -10 l 3 -11 l 5 -10 l 4 -10 l 5 -6 l 4 -7 l 6 -7 l 6 -6 l 7 -6 l 7 -6 l 6 -5 l 7 -5 l 6 -4 l 7 -5 l 7 -4 l 8 -4 l 7 -4 l 8 -4 l 8 -3 l 7 -2 l 8 -3 l 8 -2 l 9 -3 l 10 -2 l 9 -2 l 10 -1 l 8 -2 l 9 0 l 16 -2 l 9 0 l 9 -1 l 25 0 l 8 -1 l 20 0 l 11 -1 l 38 0 l 9 1 l 9 1 l 10 2 l 8 2 l 8 2 l 8 2 l 9 4 l 9 4 l 9 4 l 10 6 l 9 6 l 7 4 l 7 6 l 9 6 l 8 7 l 8 7 l 8 7 l 6 7 l 6 6 l 5 6 l 5 7 l 4 8 l 4 7 l 3 8 l 3 8 l 4 14 l 2 7 l 2 8 l 2 9 l 1 9 l 2 10 l 1 9 l 1 10 l 0 10 l 1 10 l 0 10 l -1 12 l -1 12 l -1 12 l -2 12 l -3 11 l -3 9 l -8 18 l -6 9 l -7 8 l -8 8 l -8 7 l -8 7 l -9 5 l -7 4 l -8 4 l -9 4 l -10 3 l -10 4 l -10 3 l -11 3 l -10 2 l -11 2 l -10 2 l -10 1 l -11 1 l -12 1 l -13 1 l -13 1 l -13 1 l -48 0 l -11 -1 l -11 0 l -12 -1 l -11 -1 l -12 -2 l -12 -2 l -11 -2 l -10 -2 l -10 -3 l -9 -3 l -10 -5 l -11 -5 l -11 -6 l -10 -8 l -10 -8 l -9 -8 l -8 -8 l -8 -8 l -7 -8 l -7 -9 l -6 -10 l -7 -10 l -6 -10 l -5 -10 l -4 -9 l -3 -8 l -4 -10 l -3 -10 l -2 -10 l -1 -9 l -1 -8 l -1 -7 l -1 -6 l -2 -14 Z" />
+<path d="M 1481 6669 l 1 1 l 5 3 l 12 7 l 17 10 l 18 10 l 17 10 l 16 9 l 13 7 l 13 6 l 12 5 l 10 4 l 22 8 l 12 3 l 12 4 l 13 3 l 13 3 l 13 3 l 13 2 l 12 3 l 12 1 l 12 2 l 13 2 l 12 1 l 14 2 l 14 1 l 15 1 l 16 1 l 15 1 l 16 1 l 15 0 l 15 1 l 93 0 l 15 -1 l 30 0 l 15 -1 l 15 0 l 30 -2 l 15 0 l 14 -1 l 17 0 l 18 -1 l 38 -2 l 19 0 l 19 -1 l 18 -1 l 17 -1 l 15 0 l 13 -1 l 11 0 l 9 -1 l 16 0 l 1 -1 l 3 0 l -1 1 l -7 0" />
+<path d="M 3533 6267 l 0 1 l 1 7 l 1 14 l 1 16 l 1 15 l 1 11 l 0 18 l -2 10 l -1 9 l -3 9 l -3 8 l -4 7 l -3 6 l -5 6 l -5 6 l -6 7 l -6 6 l -7 5 l -7 5 l -6 3 l -6 4 l -8 3 l -8 4 l -10 3 l -9 3 l -10 3 l -10 3 l -9 2 l -10 2 l -10 3 l -13 3 l -13 3 l -14 4 l -15 4 l -16 5 l -15 4 l -17 6 l -12 4 l -14 5 l -15 5 l -17 7 l -19 7 l -22 8 l -24 10 l -25 10 l -25 9 l -23 9 l -16 7 l -11 4 l -4 2 l -1 0" />
+<path d="M 3983 6181 l 0 5 l 1 10 l 2 15 l 1 19 l 2 20 l 2 18 l 1 16 l 1 15 l 1 12 l 1 11 l 1 11 l 1 12 l 0 12 l 1 12 l 0 44 l -1 10 l 0 8 l -1 8 l -2 9 l -3 9 l -3 8 l -4 9 l -5 7 l -5 7 l -6 6 l -6 5 l -7 4 l -8 4 l -10 4 l -10 5 l -12 4 l -12 3 l -11 4 l -12 4 l -11 2 l -10 4 l -12 3 l -13 4 l -13 3 l -14 4 l -14 4 l -14 3 l -13 3 l -13 3 l -11 2 l -12 3 l -12 2 l -14 2 l -14 3 l -15 3 l -15 4 l -15 3 l -16 4 l -15 5 l -16 4 l -16 5 l -12 5 l -13 4 l -14 5 l -15 6 l -17 7 l -18 8 l -21 9 l -23 10 l -23 10 l -23 11 l -22 9 l -18 8 l -13 6 l -7 3 l -4 2" />
+<path style="fill:rgb(100%,100%,100%);" d="M 2263 6883 l -3 7 l -4 18 l -2 8 l 0 9 l -1 8 l 0 9 l -1 9 l 0 21 l 1 10 l 0 9 l 1 9 l 0 9 l 2 9 l 1 9 l 2 9 l 3 8 l 2 5 l 3 6 l 4 7 l 6 7 l 7 7 l 8 8 l 9 7 l 11 8 l 8 5 l 10 5 l 10 6 l 12 7 l 12 6 l 14 7 l 14 7 l 14 6 l 14 7 l 13 5 l 13 6 l 13 5 l 13 4 l 13 4 l 13 5 l 14 4 l 15 4 l 15 3 l 16 4 l 32 6 l 16 3 l 17 2 l 16 2 l 15 2 l 15 1 l 17 2 l 17 2 l 18 1 l 20 2 l 19 1 l 20 2 l 38 2 l 19 2 l 34 2 l 16 1 l 16 0 l 16 1 l 16 1 l 16 1 l 17 1 l 17 1 l 17 0 l 18 1 l 17 1 l 17 1 l 17 0 l 17 1 l 16 1 l 17 1 l 14 0 l 16 1 l 15 0 l 17 1 l 18 1 l 18 0 l 18 1 l 19 0 l 18 1 l 19 0 l 18 1 l 97 0 l 17 -1 l 17 0 l 17 -1 l 17 -1 l 18 -1 l 18 -1 l 18 -2 l 18 -1 l 18 -2 l 17 -1 l 17 -2 l 17 -2 l 17 -2 l 30 -4 l 16 -2 l 17 -2 l 18 -2 l 18 -2 l 19 -3 l 19 -2 l 18 -3 l 18 -3 l 18 -2 l 17 -3 l 17 -2 l 15 -3 l 15 -2 l 14 -2 l 15 -3 l 15 -3 l 15 -3 l 15 -3 l 15 -3 l 15 -3 l 14 -3 l 14 -3 l 14 -4 l 14 -3 l 12 -4 l 13 -3 l 11 -4 l 12 -3 l 12 -4 l 12 -3 l 12 -5 l 13 -4 l 14 -5 l 28 -10 l 15 -5 l 14 -6 l 15 -5 l 14 -6 l 14 -5 l 13 -6 l 14 -5 l 13 -6 l 14 -5 l 15 -7 l 15 -6 l 15 -7 l 16 -6 l 16 -7 l 16 -7 l 16 -7 l 14 -6 l 15 -7 l 13 -6 l 13 -5 l 12 -5 l 13 -6 l 13 -6 l 13 -6 l 13 -6 l 13 -6 l 12 -5 l 11 -5 l 11 -5 l 9 -5 l 9 -4 l 8 -3 l 7 -3 l 12 -6 l 10 -6 l 10 -5 l 8 -5 l 6 -5 l 5 -5 l 4 -5 l 5 -7 l 4 -7 l 3 -7 l 3 -7 l 2 -7 l 1 -6 l 1 -7 l 0 -7 l 1 -7 l -1 -7 l 0 -6 l -1 -6 l 0 -7 l -2 -14 l 0 -7 l -1 -6 l 0 -7 l -1 -7 l 0 -8 l -1 -9 l 0 -8 l -1 -9 l -1 -5 l 0 -6 l -2 -6 l -2 -5 l -2 -6 l -3 -5 l -8 -6 l -5 -2 l -13 0 l -8 2 l -10 4 l -11 4 l -12 6 l -14 6 l -14 7 l -14 8 l -14 7 l -14 8 l -13 6 l -13 7 l -14 7 l -15 7 l -16 7 l -16 8 l -16 7 l -15 8 l -16 6 l -14 7 l -14 6 l -12 5 l -13 5 l -13 5 l -13 5 l -13 5 l -13 5 l -14 5 l -13 4 l -14 4 l -12 5 l -13 4 l -12 3 l -12 4 l -11 3 l -11 3 l -12 4 l -12 3 l -13 4 l -14 4 l -14 4 l -15 3 l -15 4 l -15 4 l -14 3 l -15 4 l -14 3 l -15 4 l -15 3 l -16 3 l -16 3 l -17 4 l -18 3 l -19 4 l -19 3 l -19 4 l -19 3 l -19 3 l -17 2 l -17 3 l -17 2 l -15 3 l -16 1 l -32 4 l -16 2 l -16 2 l -17 1 l -17 2 l -17 1 l -16 1 l -16 1 l -16 1 l -14 1 l -15 1 l -14 1 l -14 1 l -15 1 l -15 0 l -16 1 l -17 1 l -18 1 l -18 0 l -38 2 l -19 1 l -19 0 l -19 1 l -19 0 l -19 1 l -16 0 l -16 1 l -17 0 l -18 1 l -19 0 l -19 1 l -20 0 l -20 1 l -63 0 l -20 1 l -112 0 l -19 -1 l -19 0 l -19 -1 l -20 0 l -20 -1 l -19 -1 l -20 -1 l -19 -1 l -19 -1 l -18 -1 l -17 -2 l -17 -1 l -15 -1 l -14 -2 l -14 -1 l -12 -1 l -17 -3 l -16 -2 l -15 -2 l -15 -2 l -15 -3 l -15 -3 l -14 -3 l -13 -3 l -12 -3 l -11 -2 l -10 -3 l -10 -3 l -11 -3 l -12 -4 l -12 -4 l -11 -4 l -12 -4 l -11 -4 l -20 -8 l -8 -4 l -7 -4 l -9 -5 l -9 -5 l -8 -6 l -8 -5 l -8 -6 l -7 -5 l -6 -5 l -5 -5 l -8 -6 l -8 -6 l -8 -6 l -8 -5 l -7 -5 l -5 -4 l -4 -3 l -4 -3 l -4 -2 l -3 -2 l -4 -1 l -3 0 l -3 1 l -3 2 l -5 4 l -5 6 l -6 8 l -5 9 Z" />
+<path style="fill:rgb(100%,100%,100%);stroke-width:15;" d="M 4281 6302 l 7 -6 l 9 -5 l 8 -4 l 9 -4 l 8 -2 l 8 -1 l 7 -1 l 7 0 l 8 1 l 7 2 l 7 2 l 7 3 l 7 3 l 7 4 l 7 6 l 14 12 l 6 7 l 6 7 l 6 8 l 6 9 l 5 10 l 4 10 l 3 10 l 1 7 l 1 8 l 1 9 l 0 10 l -1 10 l -2 18 l -1 9 l -2 8 l -2 9 l -3 9 l -3 9 l -3 10 l -8 16 l -4 8 l -5 6 l -5 7 l -7 7 l -6 7 l -8 6 l -7 5 l -7 3 l -7 4 l -9 2 l -11 2 l -10 0 l -11 -1 l -10 -2 l -9 -2 l -9 -3 l -9 -4 l -9 -5 l -8 -4 l -8 -5 l -6 -5 l -7 -5 l -5 -5 l -6 -5 l -5 -6 l -4 -6 l -3 -5 l -3 -7 l -3 -6 l -2 -8 l -1 -8 l -1 -8 l 0 -8 l -1 -8 l 1 -9 l 0 -9 l 1 -10 l 2 -9 l 1 -7 l 2 -8 l 1 -8 l 6 -16 l 4 -9 l 4 -7 l 4 -7 l 4 -6 l 5 -8 l 6 -7 l 6 -7 l 6 -7 l 6 -6 Z" />
+<g style="stroke:rgb(0%,100%,100%);">
+<path d="M 3248 6546 l 6 0 l 11 1 l 15 1 l 16 2 l 16 2 l 14 1 l 12 2 l 11 2 l 10 3 l 10 2 l 11 4 l 12 4 l 14 6 l 16 6 l 16 7 l 15 7 l 11 4 l 5 3 l 1 0" />
+<path d="M 3095 6246 l 14 0 l 14 1 l 18 1 l 18 0 l 18 1 l 16 2 l 14 1 l 13 1 l 12 2 l 12 2 l 12 3 l 13 3 l 14 3 l 16 5 l 18 5 l 20 6 l 21 7 l 20 6 l 16 6 l 11 3 l 4 2 l 1 0" />
+<path d="M 3599 6276 l 1 0 l 5 1 l 11 1 l 17 1 l 21 2 l 22 2 l 21 2 l 20 2 l 17 2 l 15 2 l 14 2 l 14 2 l 14 2 l 14 3 l 16 2 l 17 4 l 20 3 l 21 5 l 23 4 l 22 5 l 18 3 l 11 3 l 5 1 l 1 0" />
+<path d="M 3440 6504 l 45 0 l 15 1 l 13 0 l 12 1 l 10 1 l 10 1 l 10 2 l 10 2 l 12 3 l 13 3 l 16 5 l 16 5 l 15 4 l 10 3 l 5 2 l 1 0" />
+<path d="M 3560 6402 l 1 0 l 5 1 l 12 1 l 19 1 l 23 2 l 24 2 l 22 2 l 20 2 l 18 2 l 16 2 l 14 2 l 13 2 l 13 2 l 14 2 l 13 3 l 32 6 l 19 5 l 19 4 l 18 4 l 15 4 l 9 2 l 4 1 l 1 0" />
+<path d="M 2861 6429 l 2 0 l 3 1 l 6 1 l 9 1 l 6 1 l 7 1 l 8 1 l 10 2 l 11 2 l 12 3 l 12 2 l 12 3 l 12 3 l 12 4 l 10 3 l 11 3 l 12 4 l 13 5 l 15 5 l 16 6 l 18 7 l 17 6 l 14 6 l 8 3 l 4 2 l 1 0" />
+<path d="M 2594 6492 l 6 0 l 11 1 l 17 0 l 21 1 l 22 1 l 21 2 l 20 1 l 17 1 l 16 2 l 14 1 l 15 2 l 12 2 l 13 2 l 14 3 l 15 3 l 17 3 l 19 4 l 20 5 l 22 5 l 21 5 l 18 4 l 14 3 l 9 2 l 3 1 l 1 0" />
+<path d="M 3023 6360 l 1 0 l 4 1 l 9 1 l 15 3 l 18 3 l 19 3 l 18 3 l 16 3 l 15 3 l 13 3 l 12 2 l 12 3 l 12 3 l 26 8 l 15 4 l 18 6 l 19 6 l 20 6 l 19 7 l 16 5 l 10 3 l 4 2 l 1 0" />
+</g>
+</g>
+<g style="stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;stroke-linecap:butt;stroke-linejoin:miter;fill-rule:nonzero;fill-opacity:1;stroke-width:7.5;">
+<path style="fill:rgb(0%,0%,0%);" d="M 126 31 C 94 159 12 248 -58 231 C -127 214 -158 96 -126 -32 C -94 -159 -12 -248 58 -231 C 127 -214 158 -96 126 31" transform="matrix(0.035,0,0,0.035,96.18,89.005)"/>
+<path style="fill:rgb(0%,0%,0%);" d="M 174 43 C 136 193 28 295 -68 271 C -163 247 -211 106 -174 -43 C -136 -193 -28 -295 67 -271 C 163 -247 211 -106 174 43" transform="matrix(0.035,0,0,0.035,115.185,93.205)"/>
+<path style="fill:rgb(100%,100%,100%);" d="M 54 10 C 30 147 -79 128 -54 -10 C -30 -147 79 -128 54 10" transform="matrix(0.035,0,0,0.035,114.1,91.105)"/>
+<path style="fill:rgb(100%,100%,100%);" d="M 54 10 C 30 147 -79 128 -54 -10 C -30 -147 79 -128 54 10" transform="matrix(0.035,0,0,0.035,95.83,87.325)"/>
+</g>
+</svg>
diff --git a/share/examples/BSD_daemon/beastie2.eps b/share/examples/BSD_daemon/beastie2.eps
new file mode 100644
index 000000000000..05761bf5b9b3
--- /dev/null
+++ b/share/examples/BSD_daemon/beastie2.eps
@@ -0,0 +1,2470 @@
+%!PS-Adobe-2.0 EPSF-1.2
+%%Title: beastie1.ps
+%%Creator: Sketch 0.6.12
+%%CreationDate: Sun May 26 00:37:36 2002
+%%For: Rahul Siddharthan
+%%Pages: 1
+%%DocumentFonts:
+%%BoundingBox: 385 514 545 694
+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def
+%%EndProlog
+%%Page 1 1
+
+/SketchDict 100 dict def
+SketchDict begin
+/bd { bind def } bind def
+/x { exch } bd
+/xd { exch def } bd
+/PI 3.14159265358979323846264338327 def
+/radgrad { 180 mul PI div } bd
+/skstartmatrix matrix currentmatrix def
+/tmpmat matrix def
+/ISOLatin1Encoding dup where
+{ pop pop }
+{ [/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand
+/quoteright /parenleft /parenright /asterisk /plus /comma /minus /period
+/slash /zero /one /two /three /four /five /six /seven /eight /nine /colon
+/semicolon /less /equal /greater /question /at /A /B /C /D /E /F /G /H /I /J
+/K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /backslash
+/bracketright /asciicircum /underscore /quoteleft /a /b /c /d /e /f /g /h /i
+/j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /braceleft /bar /braceright
+/asciitilde /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+/.notdef /.notdef /dotlessi /grave /acute /circumflex /tilde /macron /breve
+/dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek
+/caron /space /exclamdown /cent /sterling /currency /yen /brokenbar /section
+/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen
+/registered /macron /degree /plusminus /twosuperior /threesuperior /acute /mu
+/paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright
+/onequarter /onehalf /threequarters /questiondown /Agrave /Aacute /Acircumflex
+/Atilde /Adieresis /Aring /AE /Ccedilla /Egrave /Eacute /Ecircumflex
+/Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde /Ograve
+/Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute
+/Ucircumflex /Udieresis /Yacute /Thorn /germandbls /agrave /aacute
+/acircumflex /atilde /adieresis /aring /ae /ccedilla /egrave /eacute
+/ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis /eth /ntilde
+/ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave
+/uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def
+}
+ifelse
+/arct dup where
+{pop pop}
+{
+/arct {arcto pop pop pop pop} bd
+}
+ifelse
+/size 0 def
+/fontname 0 def
+/newfont 0 def
+/sf {
+/size xd
+/fontname xd
+fontname findfont
+dup /Encoding get StandardEncoding eq
+{
+dup
+length dict /newfont xd
+{
+1 index
+/FID ne
+{ newfont 3 1 roll put }
+{ pop pop }
+ifelse
+} forall
+newfont /Encoding ISOLatin1Encoding put
+fontname newfont definefont
+}
+if
+size scalefont setfont
+} bd
+/pusht {matrix currentmatrix} bd
+/popt {setmatrix} bd
+/pushc {gsave} bd
+/popc {grestore} bd
+/rgb {setrgbcolor} bd
+/w { setlinewidth } bd
+/j { setlinejoin } bd
+/J { setlinecap } bd
+/d { setdash } bd
+/F { eofill } bd
+/f { closepath F } bd
+/S {
+pusht
+skstartmatrix setmatrix stroke
+popt
+} bd
+/s { closepath S } bd
+/m { moveto } bd
+/l { lineto } bd
+/c { curveto } bd
+/txt {
+/tmpmat tmpmat currentmatrix def
+dup type /arraytype eq {concat} {translate} ifelse
+0 0 m
+tmpmat
+} bd
+/T {txt x show popt} bd
+/P {txt x true charpath popt} bd
+/TP {txt x dup show 0 0 m true charpath popt} bd
+/C {newpath 0 360 arc} bd
+/R {
+2 copy m
+x 2 index l
+x 2 index x l
+l
+closepath
+} bd
+/ellipse {
+dup type /arraytype eq
+{
+pusht x concat
+0 0 1.0 C
+popt
+}
+{
+pusht 5 1 roll
+4 -1 roll concat
+newpath
+dup 2 eq {
+0 0 m
+} if
+3 1 roll
+radgrad x
+radgrad x
+0 0 1 5 -2 roll
+arc
+0 ne { closepath } if
+popt
+}
+ifelse
+} bd
+/radius1 0 def
+/radius2 0 def
+/factor 0 def
+/rect {
+dup type /arraytype eq
+{
+pusht x concat
+0 0 m 1 0 l 1 1 l 0 1 l closepath
+popt
+}
+{
+/radius2 xd
+/radius1 xd
+pusht x concat
+radius1 radius2 div 1 scale
+0 radius2 m
+0 1 radius2 1 radius2 arct
+radius2 radius1 div
+dup 1 1 index 0 radius2 arct
+0 0 0 radius2 arct
+0 0 0 1 radius2 arct
+closepath
+popt
+}
+ifelse
+} bd
+/buf 0 def
+/width 0 def
+/height 0 def
+/skcimg {
+/tmpmat tmpmat currentmatrix def
+{ concat } if
+/height xd
+/width xd
+/buf width 3 mul string def
+width height scale
+width height 8
+[width 0 0 height neg 0 height]
+{ currentfile buf readhexstring pop } bind
+false 3 colorimage
+tmpmat setmatrix
+} bd
+/skgimg {
+/tmpmat tmpmat currentmatrix def
+{ concat } if
+/height xd
+/width xd
+/buf width string def
+width height scale
+width height 8
+[width 0 0 height neg 0 height]
+{ currentfile buf readhexstring pop } bind
+image
+tmpmat setmatrix
+} bd
+/rclip {
+4 2 roll m
+dup 0 x rlineto
+x 0 rlineto
+neg 0 x rlineto
+closepath
+clip
+} bd
+/skeps {
+10 dict begin
+/sk_state save def
+concat
+3 index neg 3 index neg translate
+rclip
+0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin
+10 setmiterlimit [ ] 0 setdash
+newpath
+/sk_dict_count countdictstack def
+/sk_count count 1 sub def
+userdict begin
+/showpage { } def
+/languagelevel where
+{
+pop
+languagelevel 1 ne
+{
+false setstrokeadjust
+false setoverprint
+} if
+} if
+} bd
+/skepsend {
+count sk_count sub { pop } repeat
+countdictstack sk_dict_count sub { end } repeat
+sk_state restore
+end
+} bd
+/gradidx 0 def
+/gradient {
+3 mul array
+/gradidx 0 def
+} bd
+/$ {
+3 index gradidx 5 -1 roll put
+2 index gradidx 1 add 4 -1 roll put
+1 index gradidx 2 add 3 -1 roll put
+/gradidx gradidx 3 add def
+} bd
+/! {
+3
+{
+dup dup gradidx dup 3 1 roll 3 sub get put
+/gradidx gradidx 1 add def
+}
+repeat
+} bd
+/gradcolor {
+3 mul dup 2 add 1 exch % idx 1 idx+2
+{
+1 index exch % array array i
+get % array component
+exch % component array
+}
+for
+4 1 roll
+} bd
+/x0 0 def /y0 0 def /x1 0 def /y1 0 def
+/left 0 def /right 0 def /top 0 def /bottom 0 def
+/numcolors 0 def
+/axial {
+/y1 xd /x1 xd /y0 xd /x0 xd
+dup length 3 idiv /numcolors xd
+pusht exch % ctm array
+x0 x1 ne y0 y1 ne or
+{
+x0 y0 translate
+[x1 x0 sub y1 y0 sub dup neg 2 index 0 0] concat
+clippath flattenpath pathbbox
+/top xd /right xd /bottom xd /left xd
+newpath
+0 gradcolor rgb clippath f
+0 1 numcolors 1 sub
+{
+dup numcolors div
+3 1 roll
+gradcolor rgb
+exch
+bottom right top R f
+}
+for
+}
+if
+pop
+popt
+} bd
+/r0 0 def /r1 0 def /dr 0 def
+/radial {
+/r1 xd /r0 xd /y0 xd /x0 xd
+/dr r1 r0 sub def
+dup length 3 idiv /numcolors xd
+pusht exch % ctm array
+r0 r1 ne
+{
+x0 y0 translate
+clippath flattenpath pathbbox
+/top xd /right xd /bottom xd /left xd
+newpath
+dr 0 gt {numcolors 1 sub}{0} ifelse gradcolor rgb
+clippath f
+dr 0 gt {numcolors 1 sub -1 0} { 0 1 numcolors 1 sub} ifelse
+{
+dup numcolors div dr mul r0 add
+3 1 roll
+gradcolor rgb
+exch
+0 0 3 -1 roll C f
+}
+for
+}
+if
+pop
+popt
+} bd
+/max {
+2 copy lt {exch} if pop
+} bd
+/conical {
+pusht 5 1 roll
+3 1 roll /y0 xd /x0 xd
+x0 y0 translate
+radgrad rotate
+dup length 3 idiv /numcolors xd
+clippath flattenpath pathbbox newpath
+4 { abs 4 1 roll} repeat
+3 { max } repeat
+2 mul
+dup scale
+0 gradcolor rgb
+0 0 1 0 360 arc f
+1 1 numcolors 1 sub
+{
+dup numcolors div 180 mul
+3 1 roll
+gradcolor rgb
+exch
+0 0 moveto
+0 0 1 4 -1 roll dup neg arc
+closepath f
+}
+for
+pop
+popt
+} bd
+/XStep 0 def /YStep 0 def /imagedata 0 def /components 0 def
+/tileimage2 {
+exch 4 2 roll
+/height xd
+/width xd
+mark
+/components 2 index
+/PatternType 1
+/PaintType 1
+/TilingType 1
+/BBox [0 0 width height]
+/XStep width
+/YStep height
+/PaintProc {
+begin
+XStep YStep 8
+matrix
+imagedata
+false
+components
+colorimage
+end
+}
+counttomark 2 div cvi dup dict begin
+{ def } repeat
+pop currentdict end
+dup
+/imagedata
+4 -1 roll
+width height mul mul string
+currentfile exch readhexstring pop
+put
+exch
+makepattern
+setpattern
+clippath
+eofill
+} bd
+/tileimage1 {
+concat
+/components xd
+/height xd
+/width xd
+/imagedata
+currentfile
+width height mul components mul string
+readhexstring pop
+def
+clippath flattenpath pathbbox
+/top xd /right xd /bottom xd /left xd
+left width div floor width mul
+bottom height div floor height mul
+translate
+top bottom sub height div ceiling cvi
+{
+gsave
+right left sub width div ceiling cvi
+{
+width height 8 matrix
+components 1 eq
+{
+{ imagedata }
+image
+}
+{
+imagedata
+false components
+colorimage
+}
+ifelse
+width 0 translate
+}
+repeat
+grestore
+0 height translate
+}
+repeat
+} bd
+/makepattern where
+{
+pop
+/tileimage /tileimage2 load def
+}
+{
+/tileimage /tileimage1 load def
+}
+ifelse
+end
+
+
+10.433 setmiterlimit
+
+SketchDict begin
+newpath
+473.625 576.087 m
+473.625 576.087 478.667 569.965 478.667 569.965 c
+478.667 569.965 481.187 559.523 489.109 552.681 c
+497.032 545.838 506.214 546.198 506.214 546.198 c
+506.214 546.198 520.619 544.217 529.802 540.437 c
+538.984 536.656 538.805 536.836 542.046 533.954 c
+545.287 531.074 545.287 527.473 542.406 524.952 c
+539.525 522.431 534.484 520.27 530.522 519.911 c
+526.562 519.55 519.719 519.55 519.719 519.55 c
+519.719 519.55 524.04 523.512 524.04 523.512 c
+524.04 523.512 534.483 527.112 535.564 528.553 c
+536.644 529.994 533.943 531.794 533.943 531.794 c
+533.943 531.794 528.002 535.035 523.68 536.115 c
+519.359 537.195 499.372 540.977 499.013 540.977 c
+498.652 540.977 495.052 541.337 486.229 544.758 c
+477.406 548.18 476.146 551.24 476.146 551.24 c
+476.146 551.24 468.584 558.802 468.584 558.802 c
+468.584 558.802 473.265 576.448 473.265 576.448 c
+closepath
+0.444 0 0 rgb
+F
+newpath
+442.656 609.577 m
+442.656 609.577 443.015 603.456 443.015 603.456 c
+443.015 603.456 438.694 600.215 438.694 600.215 c
+438.694 600.215 435.093 600.935 431.132 600.575 c
+427.171 600.215 416.547 593.553 416.547 593.553 c
+416.547 593.553 420.328 587.251 420.328 587.251 c
+420.328 587.251 427.171 587.971 427.171 587.971 c
+427.171 587.971 428.251 589.051 429.691 587.971 c
+431.132 586.89 430.411 586.89 432.212 583.65 c
+434.013 580.409 433.293 579.328 433.293 579.328 c
+433.293 579.328 431.852 576.448 431.492 574.287 c
+431.132 572.126 432.932 562.764 434.733 560.963 c
+436.534 559.162 438.334 558.802 438.334 557.002 c
+438.334 555.201 438.334 545.838 438.334 545.838 c
+438.334 545.838 455.259 543.678 455.259 543.678 c
+455.259 543.678 475.785 547.999 475.785 547.999 c
+475.785 547.999 476.146 570.326 477.226 573.927 c
+478.306 577.528 479.747 577.168 480.107 581.849 c
+480.467 586.531 479.026 593.013 479.026 593.013 c
+479.026 593.013 478.667 592.652 476.506 600.215 c
+474.345 607.777 474.705 609.938 474.705 609.938 c
+474.705 609.938 475.065 615.7 475.065 615.7 c
+475.065 615.7 442.295 609.938 442.295 610.298 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.677 0 0 $
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+0.679 0 0 $
+0.685 0 0 $
+0.69 0 0 $
+0.695 0 0 $
+0.7 0 0 $
+0.706 0 0 $
+0.711 0 0 $
+0.716 0 0 $
+0.721 0 0 $
+0.727 0 0 $
+0.732 0 0 $
+0.737 0 0 $
+0.742 0 0 $
+0.748 0 0 $
+0.753 0 0 $
+0.758 0 0 $
+0.763 0 0 $
+0.769 0 0 $
+0.774 0 0 $
+0.779 0 0 $
+0.784 0 0 $
+0.79 0 0 $
+0.795 0 0 $
+0.8 0 0 $
+0.805 0 0 $
+0.811 0 0 $
+0.816 0 0 $
+0.821 0 0 $
+0.826 0 0 $
+0.832 0 0 $
+0.837 0 0 $
+0.842 0 0 $
+0.847 0 0 $
+0.853 0 0 $
+0.858 0 0 $
+0.863 0 0 $
+0.868 0 0 $
+0.874 0 0 $
+0.879 0 0 $
+439.268 598.895 68.713 0 radial
+popc
+newpath
+[14.6696 -1.68454 -2.67069 -23.6151 446.099 580.972] ellipse
+pushc
+eoclip newpath
+50 gradient
+0.778 0 0 $
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+0.788 0 0 $
+0.8 0 0 $
+0.811 0 0 $
+0.822 0 0 $
+0.834 0 0 $
+0.845 0 0 $
+0.856 0 0 $
+0.868 0 0 $
+0.879 0 0 $
+0.89 0 0 $
+0.902 0 0 $
+0.913 0 0 $
+0.925 0 0 $
+0.936 0 0 $
+0.947 0 0 $
+0.959 0 0 $
+0.97 0 0 $
+438.644 584.129 34.9312 0 radial
+popc
+newpath
+newpath
+428.972 600.575 m
+428.251 599.855 430.772 601.655 434.373 601.655 c
+437.974 601.655 439.414 600.215 439.414 600.215 c
+439.414 600.215 452.738 598.414 452.378 598.055 c
+452.018 597.694 457.059 596.253 455.619 592.293 c
+454.179 588.331 457.42 588.691 457.06 588.691 c
+456.7 588.691 445.536 593.373 442.295 596.614 c
+439.055 599.855 437.254 589.051 432.212 588.691 c
+427.171 588.331 425.01 586.89 425.01 586.89 c
+425.01 586.89 425.01 591.572 425.731 592.652 c
+426.451 593.733 428.251 598.774 428.251 598.774 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.455 0 0 $
+0.462 0 0 $
+0.47 0 0 $
+0.477 0 0 $
+0.485 0 0 $
+0.492 0 0 $
+0.499 0 0 $
+0.507 0 0 $
+0.514 0 0 $
+0.522 0 0 $
+0.529 0 0 $
+0.536 0 0 $
+0.544 0 0 $
+0.551 0 0 $
+0.559 0 0 $
+0.566 0 0 $
+0.574 0 0 $
+0.581 0 0 $
+0.588 0 0 $
+0.596 0 0 $
+0.603 0 0 $
+0.611 0 0 $
+0.618 0 0 $
+0.625 0 0 $
+0.633 0 0 $
+0.64 0 0 $
+0.648 0 0 $
+0.655 0 0 $
+0.662 0 0 $
+0.67 0 0 $
+0.677 0 0 $
+0.685 0 0 $
+0.692 0 0 $
+0.699 0 0 $
+0.707 0 0 $
+0.714 0 0 $
+0.722 0 0 $
+0.729 0 0 $
+0.737 0 0 $
+0.744 0 0 $
+0.751 0 0 $
+0.759 0 0 $
+0.766 0 0 $
+0.774 0 0 $
+0.781 0 0 $
+0.788 0 0 $
+0.796 0 0 $
+0.803 0 0 $
+0.811 0 0 $
+0.818 0 0 $
+425.429 602.455 456.669 586.091 axial
+popc
+newpath
+newpath
+474.975 612.368 m
+474.975 612.368 474.616 608.408 474.795 607.687 c
+474.975 606.967 476.596 599.945 476.596 599.765 c
+476.596 599.585 479.657 591.122 479.657 591.122 c
+479.657 591.122 480.557 587.161 480.197 582.66 c
+479.837 578.158 479.117 578.698 477.856 574.917 c
+476.596 571.136 476.596 565.914 476.596 565.914 c
+476.596 565.914 476.235 556.371 476.056 556.371 c
+475.876 556.371 476.596 551.87 475.696 552.951 c
+474.795 554.031 469.213 556.011 469.034 556.011 c
+468.854 556.011 457.87 556.011 457.87 556.011 c
+457.87 556.011 450.128 556.011 450.128 556.011 c
+450.128 556.011 445.086 556.732 444.906 556.192 c
+444.726 555.651 449.228 560.873 452.828 560.333 c
+456.43 559.793 454.99 565.915 454.99 566.275 c
+454.99 566.635 463.631 567.535 463.812 569.875 c
+463.992 572.216 433.563 578.698 431.763 585 c
+429.962 591.302 446.887 579.598 445.086 585.721 c
+443.286 591.843 459.851 583.92 460.931 586.441 c
+462.012 588.961 465.793 586.62 467.773 588.961 c
+469.754 591.302 469.394 591.482 470.114 593.823 c
+470.834 596.163 470.654 597.964 470.474 600.125 c
+470.294 602.285 469.394 605.706 469.394 606.066 c
+469.394 606.427 468.314 606.607 465.612 607.507 c
+462.911 608.408 458.05 606.787 454.269 607.147 c
+450.488 607.507 449.587 609.488 449.587 609.488 c
+449.587 609.488 475.336 612.909 475.336 612.909 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+1 0 0 $
+0.984 0 0 $
+0.968 0 0 $
+0.951 0 0 $
+0.935 0 0 $
+0.919 0 0 $
+0.903 0 0 $
+0.886 0 0 $
+0.87 0 0 $
+0.854 0 0 $
+0.838 0 0 $
+0.821 0 0 $
+0.805 0 0 $
+0.789 0 0 $
+0.773 0 0 $
+0.756 0 0 $
+0.74 0 0 $
+0.724 0 0 $
+0.708 0 0 $
+0.691 0 0 $
+0.675 0 0 $
+0.659 0 0 $
+0.643 0 0 $
+0.627 0 0 $
+0.61 0 0 $
+0.594 0 0 $
+0.578 0 0 $
+0.562 0 0 $
+0.545 0 0 $
+0.529 0 0 $
+0.513 0 0 $
+0.497 0 0 $
+0.48 0 0 $
+0.464 0 0 $
+0.456 0 0 $
+0.459 0 0 $
+0.461 0 0 $
+0.464 0 0 $
+0.466 0 0 $
+0.469 0 0 $
+0.472 0 0 $
+0.474 0 0 $
+0.477 0 0 $
+0.479 0 0 $
+0.482 0 0 $
+0.485 0 0 $
+0.487 0 0 $
+0.49 0 0 $
+0.492 0 0 $
+0.495 0 0 $
+424.951 602.224 486.96 563.468 axial
+popc
+newpath
+newpath
+424.29 654.951 m
+424.29 654.951 422.129 670.076 423.21 673.317 c
+424.29 676.558 427.531 679.079 430.411 681.24 c
+433.293 683.4 436.894 688.441 440.855 690.962 c
+444.816 693.483 446.706 693.483 447.337 693.483 c
+447.967 693.483 450.218 693.753 450.578 692.763 c
+450.939 691.773 450.218 690.242 449.858 690.242 c
+449.497 690.242 446.617 687.721 446.256 687.721 c
+445.897 687.721 442.205 683.49 441.935 682.32 c
+441.665 681.149 441.935 679.079 441.935 679.079 c
+441.935 679.079 443.376 675.117 443.736 675.117 c
+444.096 675.117 446.977 676.648 448.777 677.278 c
+450.578 677.908 450.668 678.088 453.459 678.358 c
+456.25 678.628 459.941 678.358 460.301 678.358 c
+460.661 678.358 468.314 677.009 468.673 677.009 c
+469.034 677.009 474.345 675.117 477.226 673.317 c
+480.107 671.517 480.647 670.256 480.647 670.256 c
+480.647 670.256 483.348 666.835 483.348 666.835 c
+483.348 666.835 485.598 666.565 486.409 665.935 c
+487.219 665.304 484.428 665.755 488.029 666.115 c
+491.63 666.475 493.971 667.375 493.971 667.375 c
+493.971 667.375 494.871 668.996 494.871 668.996 c
+494.871 668.996 495.952 671.877 495.952 672.596 c
+495.952 673.317 495.232 677.638 495.232 677.999 c
+495.232 678.358 494.151 682.32 494.151 682.32 c
+494.151 682.32 491.63 685.921 491.63 685.921 c
+491.63 685.921 490.55 686.281 490.91 686.281 c
+491.271 686.281 490.19 687.001 493.431 687.361 c
+496.672 687.721 499.013 684.841 500.273 683.76 c
+501.534 682.68 507.295 678.179 509.096 673.497 c
+510.897 668.816 510.897 664.314 510.177 661.073 c
+509.456 657.833 507.115 654.591 505.855 652.43 c
+504.595 650.27 500.993 647.389 499.192 646.309 c
+497.392 645.229 491.271 642.347 491.271 642.347 c
+491.271 642.347 490.19 641.267 489.83 639.827 c
+489.47 638.387 490.19 630.824 490.19 630.824 c
+490.19 630.824 489.83 625.422 488.029 622.901 c
+486.229 620.381 480.107 617.32 480.107 617.32 c
+480.107 617.32 476.866 614.259 474.705 612.098 c
+472.545 609.938 462.101 607.958 457.78 608.317 c
+453.459 608.678 455.619 608.317 452.738 607.957 c
+449.858 607.597 446.617 607.777 446.617 607.777 c
+446.617 607.777 443.015 607.777 438.694 609.577 c
+434.373 611.378 433.653 612.098 433.293 612.459 c
+432.932 612.818 426.991 617.68 426.991 617.68 c
+426.991 617.68 422.849 620.381 421.049 621.101 c
+419.248 621.821 417.448 625.063 416.368 627.223 c
+415.287 629.384 415.287 631.544 415.287 631.544 c
+415.287 631.544 414.026 633.885 416.547 637.846 c
+419.068 641.807 419.068 639.467 421.589 643.788 c
+424.11 648.109 421.949 643.068 423.39 647.389 c
+424.83 651.71 424.29 657.112 424.29 657.112 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.626 0 0 $
+0.631 0 0 $
+0.636 0 0 $
+0.641 0 0 $
+0.645 0 0 $
+0.65 0 0 $
+0.655 0 0 $
+0.66 0 0 $
+0.665 0 0 $
+0.67 0 0 $
+0.674 0 0 $
+0.681 0 0 $
+0.689 0 0 $
+0.698 0 0 $
+0.706 0 0 $
+0.714 0 0 $
+0.723 0 0 $
+0.731 0 0 $
+0.74 0 0 $
+0.748 0 0 $
+0.756 0 0 $
+0.765 0 0 $
+0.773 0 0 $
+0.782 0 0 $
+0.79 0 0 $
+0.798 0 0 $
+0.807 0 0 $
+0.815 0 0 $
+0.824 0 0 $
+0.832 0 0 $
+0.84 0 0 $
+0.849 0 0 $
+0.857 0 0 $
+0.866 0 0 $
+0.874 0 0 $
+0.882 0 0 $
+0.891 0 0 $
+0.899 0 0 $
+0.908 0 0 $
+0.916 0 0 $
+0.924 0 0 $
+0.933 0 0 $
+0.941 0 0 $
+0.95 0 0 $
+0.958 0 0 $
+0.966 0 0 $
+0.975 0 0 $
+0.983 0 0 $
+0.992 0 0 $
+1 0 0 $
+446.857 653.484 78.4847 0 radial
+popc
+newpath
+newpath
+425.731 647.389 m
+425.731 647.389 426.631 652.971 426.631 652.971 c
+426.631 652.971 428.611 656.032 428.611 656.392 c
+428.611 656.752 430.772 660.173 432.572 661.973 c
+434.373 663.774 439.055 666.475 439.055 666.475 c
+439.055 666.475 441.935 667.375 442.656 666.115 c
+443.376 664.855 443.196 665.755 442.475 663.594 c
+441.755 661.433 440.135 658.913 440.135 658.913 c
+440.135 658.913 438.334 656.752 437.614 653.871 c
+436.894 650.99 436.894 650.27 436.894 650.27 c
+436.894 650.27 436.173 647.029 436.173 647.029 c
+436.173 647.029 434.373 643.788 434.373 643.788 c
+434.373 643.788 433.653 641.988 433.653 641.988 c
+433.653 641.988 431.132 640.907 431.132 640.907 c
+431.132 640.907 427.531 641.988 427.531 641.988 c
+427.531 641.988 425.91 644.148 425.731 645.229 c
+425.55 646.309 425.731 647.389 425.731 647.389 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.737 0.737 0.737 $
+0.746 0.746 0.746 $
+0.755 0.755 0.755 $
+0.764 0.764 0.764 $
+0.773 0.773 0.773 $
+0.782 0.782 0.782 $
+0.792 0.792 0.792 $
+0.801 0.801 0.801 $
+0.81 0.81 0.81 $
+0.819 0.819 0.819 $
+0.828 0.828 0.828 $
+0.837 0.837 0.837 $
+0.846 0.846 0.846 $
+0.855 0.855 0.855 $
+0.864 0.864 0.864 $
+0.873 0.873 0.873 $
+0.883 0.883 0.883 $
+0.892 0.892 0.892 $
+0.901 0.901 0.901 $
+0.91 0.91 0.91 $
+0.919 0.919 0.919 $
+0.928 0.928 0.928 $
+0.937 0.937 0.937 $
+0.946 0.946 0.946 $
+0.955 0.955 0.955 $
+0.964 0.964 0.964 $
+0.974 0.974 0.974 $
+0.983 0.983 0.983 $
+0.992 0.992 0.992 $
+1 1 1 $
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+427.937 655.141 20.8071 0 radial
+popc
+newpath
+newpath
+442.205 653.961 m
+442.205 653.961 444.546 658.283 446.347 660.623 c
+448.147 662.964 447.967 664.044 450.488 664.585 c
+453.009 665.125 454.089 664.945 456.25 663.324 c
+458.41 661.703 460.031 659.183 460.391 656.122 c
+460.751 653.061 460.571 644.598 459.671 641.898 c
+458.771 639.197 456.609 634.695 455.17 633.435 c
+453.729 632.175 453.729 631.094 450.308 630.734 c
+446.887 630.374 446.707 630.374 444.546 631.454 c
+442.386 632.535 440.585 634.695 440.585 634.876 c
+440.585 635.055 438.424 639.737 438.424 641.537 c
+438.424 643.338 440.405 650.54 440.405 650.72 c
+440.405 650.9 442.566 654.502 442.566 654.502 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.737 0.737 0.737 $
+0.746 0.746 0.746 $
+0.755 0.755 0.755 $
+0.764 0.764 0.764 $
+0.773 0.773 0.773 $
+0.782 0.782 0.782 $
+0.792 0.792 0.792 $
+0.801 0.801 0.801 $
+0.81 0.81 0.81 $
+0.819 0.819 0.819 $
+0.828 0.828 0.828 $
+0.837 0.837 0.837 $
+0.846 0.846 0.846 $
+0.855 0.855 0.855 $
+0.864 0.864 0.864 $
+0.873 0.873 0.873 $
+0.883 0.883 0.883 $
+0.892 0.892 0.892 $
+0.901 0.901 0.901 $
+0.91 0.91 0.91 $
+0.919 0.919 0.919 $
+0.928 0.928 0.928 $
+0.937 0.937 0.937 $
+0.946 0.946 0.946 $
+0.955 0.955 0.955 $
+0.964 0.964 0.964 $
+0.974 0.974 0.974 $
+0.983 0.983 0.983 $
+0.992 0.992 0.992 $
+1 1 1 $
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+440.796 648.261 26.5629 0 radial
+popc
+newpath
+[5.36527 -1.21705 -1.81379 -8.99236 443.376 642.978] ellipse
+pushc
+eoclip newpath
+50 gradient
+0 0 0 $
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+0.013 0.013 0.013 $
+0.045 0.045 0.045 $
+0.078 0.078 0.078 $
+0.11 0.11 0.11 $
+0.143 0.143 0.143 $
+0.176 0.176 0.176 $
+0.208 0.208 0.208 $
+0.241 0.241 0.241 $
+0.273 0.273 0.273 $
+0.306 0.306 0.306 $
+0.338 0.338 0.338 $
+0.371 0.371 0.371 $
+0.403 0.403 0.403 $
+0.436 0.436 0.436 $
+0.468 0.468 0.468 $
+0.501 0.501 0.501 $
+0.533 0.533 0.533 $
+0.566 0.566 0.566 $
+442.162 646.91 14.7128 0 radial
+popc
+newpath
+[3.50831 -0.944447 -1.42027 -6.48433 429.085 647.862] ellipse
+pushc
+eoclip newpath
+50 gradient
+0 0 0 $
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+0.013 0.013 0.013 $
+0.045 0.045 0.045 $
+0.078 0.078 0.078 $
+0.11 0.11 0.11 $
+0.143 0.143 0.143 $
+0.176 0.176 0.176 $
+0.208 0.208 0.208 $
+0.241 0.241 0.241 $
+0.273 0.273 0.273 $
+0.306 0.306 0.306 $
+0.338 0.338 0.338 $
+0.371 0.371 0.371 $
+0.403 0.403 0.403 $
+0.436 0.436 0.436 $
+0.468 0.468 0.468 $
+0.501 0.501 0.501 $
+0.533 0.533 0.533 $
+0.566 0.566 0.566 $
+427.643 651.138 11.1324 0 radial
+popc
+newpath
+[0.500026 -0.204317 -0.340534 -0.833389 428.161 651.08] ellipse
+1 1 1 rgb
+F
+[0.681665 -0.232484 -0.435916 -1.27814 442.408 647.052] ellipse
+F
+newpath
+493.791 685.561 m
+493.791 685.561 495.592 681.96 497.752 678.358 c
+499.913 674.757 501.354 672.957 500.633 669.716 c
+499.913 666.475 495.952 662.874 495.592 662.874 c
+495.232 662.874 490.91 657.832 486.229 657.472 c
+481.547 657.112 479.387 658.913 476.866 656.032 c
+474.345 653.151 472.545 647.749 471.825 644.868 c
+471.104 641.988 473.985 638.026 472.905 632.625 c
+471.825 627.223 471.104 623.262 469.304 621.461 c
+467.503 619.66 465.702 616.06 462.462 614.619 c
+459.221 613.179 457.06 612.098 457.06 612.098 c
+457.06 612.098 442.295 610.298 442.295 610.298 c
+442.295 610.298 446.256 609.577 450.218 609.577 c
+454.179 609.577 455.079 608.498 458.68 608.857 c
+462.282 609.218 467.683 610.118 471.645 611.558 c
+475.606 612.999 475.426 615.159 479.747 617.68 c
+484.068 620.201 488.03 620.561 489.83 626.323 c
+491.63 632.085 487.849 638.747 491.09 641.448 c
+494.331 644.148 501.534 646.669 504.054 649.91 c
+506.575 653.151 510.717 657.652 510.356 665.575 c
+509.996 673.497 506.755 673.677 504.234 677.638 c
+501.713 681.599 493.791 685.921 493.791 685.921 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+1 0 0 $
+0.99 0 0 $
+0.98 0 0 $
+0.97 0 0 $
+0.96 0 0 $
+0.95 0 0 $
+0.94 0 0 $
+0.93 0 0 $
+0.92 0 0 $
+0.91 0 0 $
+0.9 0 0 $
+0.89 0 0 $
+0.88 0 0 $
+0.87 0 0 $
+0.86 0 0 $
+0.85 0 0 $
+0.831 0 0 $
+0.809 0 0 $
+0.788 0 0 $
+0.767 0 0 $
+0.745 0 0 $
+0.724 0 0 $
+0.702 0 0 $
+0.681 0 0 $
+0.66 0 0 $
+0.638 0 0 $
+0.617 0 0 $
+0.595 0 0 $
+0.574 0 0 $
+0.553 0 0 $
+0.531 0 0 $
+0.51 0 0 $
+0.488 0 0 $
+0.467 0 0 $
+0.455 0 0 $
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+434.343 660.475 518.33 634.229 axial
+popc
+newpath
+newpath
+443.736 692.043 m
+443.736 692.043 438.334 684.841 437.974 684.841 c
+437.614 684.841 434.013 681.24 432.212 677.638 c
+430.411 674.037 432.212 668.996 432.212 668.996 c
+432.212 668.996 428.251 661.794 428.251 661.794 c
+428.251 661.794 434.733 668.996 434.733 668.996 c
+434.733 668.996 437.974 673.317 437.974 673.317 c
+437.974 673.317 440.135 673.317 441.575 674.397 c
+443.015 675.478 439.775 678.719 440.135 680.519 c
+440.495 682.32 441.576 685.2 444.816 687.361 c
+448.057 689.522 449.228 689.882 449.498 691.053 c
+449.768 692.223 448.507 692.673 448.507 692.673 c
+448.507 692.673 445.806 692.493 444.456 692.403 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.848 0 0 $
+0.836 0 0 $
+0.825 0 0 $
+0.813 0 0 $
+0.801 0 0 $
+0.789 0 0 $
+0.778 0 0 $
+0.766 0 0 $
+0.754 0 0 $
+0.743 0 0 $
+0.731 0 0 $
+0.719 0 0 $
+0.707 0 0 $
+0.696 0 0 $
+0.684 0 0 $
+0.672 0 0 $
+0.661 0 0 $
+0.649 0 0 $
+0.637 0 0 $
+0.626 0 0 $
+0.614 0 0 $
+0.602 0 0 $
+0.59 0 0 $
+0.579 0 0 $
+0.567 0 0 $
+0.555 0 0 $
+0.544 0 0 $
+0.532 0 0 $
+0.52 0 0 $
+0.508 0 0 $
+0.497 0 0 $
+0.485 0 0 $
+0.473 0 0 $
+0.462 0 0 $
+0.452 0 0 $
+0.444 0 0 $
+0.436 0 0 $
+0.428 0 0 $
+0.42 0 0 $
+0.412 0 0 $
+0.404 0 0 $
+0.396 0 0 $
+0.388 0 0 $
+0.38 0 0 $
+0.373 0 0 $
+0.365 0 0 $
+0.357 0 0 $
+0.349 0 0 $
+0.341 0 0 $
+0.333 0 0 $
+424.233 685.785 453.554 668.682 axial
+popc
+newpath
+newpath
+442.656 672.957 m
+442.295 672.957 443.736 669.716 444.456 669.716 c
+445.176 669.716 445.176 671.877 446.977 674.037 c
+448.777 676.198 455.98 676.918 455.98 675.838 c
+455.98 674.758 450.578 671.516 451.298 670.796 c
+452.018 670.076 456.339 670.796 458.14 669.716 c
+459.941 668.636 462.462 662.874 463.542 663.234 c
+464.622 663.594 464.622 669.356 467.503 669.716 c
+470.384 670.076 481.367 663.594 484.248 663.234 c
+487.129 662.874 493.161 667.375 493.161 667.015 c
+493.161 666.655 487.669 665.214 484.788 666.475 c
+481.907 667.736 480.287 672.056 476.326 673.857 c
+472.365 675.658 469.124 676.558 465.882 677.638 c
+462.641 678.719 454.899 678.538 453.999 678.538 c
+453.099 678.538 446.976 676.918 446.617 676.558 c
+446.256 676.198 442.295 673.317 442.295 673.317 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.929 0 0 $
+0.915 0 0 $
+0.901 0 0 $
+0.887 0 0 $
+0.873 0 0 $
+0.858 0 0 $
+0.844 0 0 $
+0.83 0 0 $
+0.816 0 0 $
+0.802 0 0 $
+0.788 0 0 $
+0.774 0 0 $
+0.76 0 0 $
+0.745 0 0 $
+0.731 0 0 $
+0.717 0 0 $
+0.703 0 0 $
+0.689 0 0 $
+0.675 0 0 $
+0.661 0 0 $
+0.647 0 0 $
+0.632 0 0 $
+0.618 0 0 $
+0.604 0 0 $
+0.59 0 0 $
+0.576 0 0 $
+0.562 0 0 $
+0.548 0 0 $
+0.534 0 0 $
+0.519 0 0 $
+0.505 0 0 $
+0.491 0 0 $
+0.477 0 0 $
+0.463 0 0 $
+0.452 0 0 $
+0.444 0 0 $
+0.436 0 0 $
+0.428 0 0 $
+0.42 0 0 $
+0.412 0 0 $
+0.404 0 0 $
+0.396 0 0 $
+0.388 0 0 $
+0.38 0 0 $
+0.373 0 0 $
+0.365 0 0 $
+0.357 0 0 $
+0.349 0 0 $
+0.341 0 0 $
+0.333 0 0 $
+461.749 655.601 473.707 686.162 axial
+popc
+newpath
+[8.98414 -1.89974 -1.2665 -5.98943 433.112 634.785] ellipse
+pushc
+eoclip newpath
+50 gradient
+0.424 0 0 $
+0.425 0 0 $
+0.426 0 0 $
+0.427 0 0 $
+0.428 0 0 $
+0.43 0 0 $
+0.431 0 0 $
+0.432 0 0 $
+0.433 0 0 $
+0.434 0 0 $
+0.435 0 0 $
+0.436 0 0 $
+0.437 0 0 $
+0.439 0 0 $
+0.44 0 0 $
+0.441 0 0 $
+0.442 0 0 $
+0.443 0 0 $
+0.444 0 0 $
+0.445 0 0 $
+0.446 0 0 $
+0.448 0 0 $
+0.449 0 0 $
+0.45 0 0 $
+0.451 0 0 $
+0.452 0 0 $
+0.453 0 0 $
+0.454 0 0 $
+0.463 0 0 $
+0.489 0 0 $
+0.515 0 0 $
+0.541 0 0 $
+0.566 0 0 $
+0.592 0 0 $
+0.618 0 0 $
+0.644 0 0 $
+0.67 0 0 $
+0.695 0 0 $
+0.721 0 0 $
+0.747 0 0 $
+0.773 0 0 $
+0.799 0 0 $
+0.824 0 0 $
+0.828 0 0 $
+!
+!
+!
+!
+!
+!
+430.304 636.461 14.3008 0 radial
+popc
+newpath
+newpath
+449.137 618.94 m
+449.137 618.94 455.259 621.461 457.78 621.822 c
+460.301 622.181 463.182 622.181 464.982 620.741 c
+466.783 619.3 466.063 617.5 465.702 617.5 c
+465.342 617.5 460.301 616.78 457.06 615.7 c
+453.819 614.619 452.018 612.098 446.977 611.738 c
+441.935 611.378 443.376 609.938 437.614 611.738 c
+431.852 613.539 431.492 613.899 429.331 616.06 c
+427.171 618.22 423.57 622.901 423.57 622.901 c
+423.57 622.901 423.21 626.863 423.21 626.863 c
+423.21 626.863 424.29 627.943 427.891 624.702 c
+431.492 621.461 433.652 622.181 437.254 619.66 c
+440.855 617.14 439.414 618.58 444.096 618.22 c
+448.777 617.86 448.417 619.3 448.417 619.3 c
+closepath
+0.636 0 0 rgb
+F
+newpath
+400.523 635.505 m
+400.523 635.505 406.285 624.702 406.285 624.702 c
+406.285 624.702 408.445 626.863 408.806 626.863 c
+409.165 626.863 412.406 623.622 412.046 621.821 c
+411.686 620.021 408.445 616.06 408.445 616.06 c
+408.445 616.06 402.323 620.741 402.323 621.101 c
+402.323 621.461 404.124 624.342 403.764 624.342 c
+403.403 624.342 395.121 626.143 395.121 626.143 c
+395.121 626.143 397.282 617.86 397.282 617.86 c
+397.282 617.86 399.442 619.301 399.442 619.301 c
+399.442 619.301 406.285 613.179 406.285 613.539 c
+406.285 613.899 404.484 609.218 400.162 608.857 c
+395.841 608.497 394.401 611.018 394.401 611.018 c
+394.401 611.018 394.761 613.899 394.761 613.899 c
+394.761 613.899 384.678 615.339 384.678 615.339 c
+384.678 615.339 385.218 610.838 390.26 607.957 c
+395.301 605.076 397.462 603.996 403.224 606.157 c
+408.985 608.317 409.346 609.758 409.346 609.758 c
+409.346 609.758 409.886 610.298 409.886 610.298 c
+409.886 610.298 415.287 605.256 415.287 605.256 c
+415.287 605.256 418.528 609.938 418.528 609.938 c
+418.528 609.938 412.766 614.259 412.766 614.259 c
+412.766 614.259 414.927 617.5 414.927 617.5 c
+414.927 617.5 416.547 621.641 415.107 625.242 c
+413.667 628.843 410.966 630.464 410.966 630.464 c
+410.966 630.464 408.445 632.625 405.564 633.705 c
+402.683 634.785 401.243 634.785 401.243 634.785 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.737 0.737 0.737 $
+0.731 0.731 0.731 $
+0.725 0.725 0.725 $
+0.718 0.718 0.718 $
+0.712 0.712 0.712 $
+0.706 0.706 0.706 $
+0.7 0.7 0.7 $
+0.694 0.694 0.694 $
+0.687 0.687 0.687 $
+0.681 0.681 0.681 $
+0.675 0.675 0.675 $
+0.669 0.669 0.669 $
+0.663 0.663 0.663 $
+0.656 0.656 0.656 $
+0.65 0.65 0.65 $
+0.644 0.644 0.644 $
+0.638 0.638 0.638 $
+0.631 0.631 0.631 $
+0.625 0.625 0.625 $
+0.619 0.619 0.619 $
+0.613 0.613 0.613 $
+0.607 0.607 0.607 $
+0.6 0.6 0.6 $
+0.594 0.594 0.594 $
+0.588 0.588 0.588 $
+0.582 0.582 0.582 $
+0.576 0.576 0.576 $
+0.569 0.569 0.569 $
+0.563 0.563 0.563 $
+0.557 0.557 0.557 $
+0.537 0.537 0.537 $
+0.514 0.514 0.514 $
+0.492 0.492 0.492 $
+0.469 0.469 0.469 $
+0.446 0.446 0.446 $
+0.424 0.424 0.424 $
+0.401 0.401 0.401 $
+0.384 0.384 0.384 $
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+382.433 631.763 420.773 608.758 axial
+popc
+newpath
+[6.26125 -1.34636 -0.426261 -8.21329 424.516 594.859] ellipse
+pushc
+eoclip newpath
+50 gradient
+0.424 0 0 $
+0.431 0 0 $
+0.438 0 0 $
+0.444 0 0 $
+0.451 0 0 $
+0.458 0 0 $
+0.465 0 0 $
+0.472 0 0 $
+0.479 0 0 $
+0.485 0 0 $
+0.492 0 0 $
+0.499 0 0 $
+0.506 0 0 $
+0.513 0 0 $
+0.519 0 0 $
+0.526 0 0 $
+0.533 0 0 $
+0.54 0 0 $
+0.547 0 0 $
+0.554 0 0 $
+0.56 0 0 $
+0.567 0 0 $
+0.574 0 0 $
+0.581 0 0 $
+0.588 0 0 $
+0.594 0 0 $
+0.601 0 0 $
+0.608 0 0 $
+0.615 0 0 $
+0.622 0 0 $
+0.628 0 0 $
+0.635 0 0 $
+0.642 0 0 $
+0.649 0 0 $
+0.656 0 0 $
+0.663 0 0 $
+0.669 0 0 $
+0.676 0 0 $
+0.683 0 0 $
+0.69 0 0 $
+0.697 0 0 $
+0.703 0 0 $
+0.71 0 0 $
+0.717 0 0 $
+0.724 0 0 $
+0.731 0 0 $
+0.738 0 0 $
+0.744 0 0 $
+0.751 0 0 $
+0.758 0 0 $
+422.275 598.188 14.4331 0 radial
+popc
+newpath
+newpath
+442.655 600.575 m
+442.655 600.575 443.376 604.536 446.256 605.256 c
+449.138 605.977 453.818 602.735 454.179 602.735 c
+454.539 602.735 458.5 603.816 463.182 602.015 c
+467.863 600.215 467.863 597.694 465.342 595.894 c
+462.822 594.093 466.063 591.932 463.542 591.573 c
+461.022 591.212 460.661 590.851 458.86 592.293 c
+457.06 593.733 455.259 599.494 454.899 599.494 c
+454.539 599.494 448.777 600.575 448.417 600.575 c
+448.057 600.575 443.015 600.215 443.015 600.215 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.778 0 0 $
+0.772 0 0 $
+0.765 0 0 $
+0.759 0 0 $
+0.752 0 0 $
+0.746 0 0 $
+0.74 0 0 $
+0.733 0 0 $
+0.727 0 0 $
+0.721 0 0 $
+0.714 0 0 $
+0.708 0 0 $
+0.701 0 0 $
+0.695 0 0 $
+0.689 0 0 $
+0.682 0 0 $
+0.676 0 0 $
+0.669 0 0 $
+0.663 0 0 $
+0.657 0 0 $
+0.65 0 0 $
+0.644 0 0 $
+0.637 0 0 $
+0.631 0 0 $
+0.625 0 0 $
+0.618 0 0 $
+0.612 0 0 $
+0.606 0 0 $
+0.599 0 0 $
+0.593 0 0 $
+0.586 0 0 $
+0.58 0 0 $
+0.574 0 0 $
+0.567 0 0 $
+0.561 0 0 $
+0.554 0 0 $
+0.548 0 0 $
+0.542 0 0 $
+0.535 0 0 $
+0.529 0 0 $
+0.522 0 0 $
+0.516 0 0 $
+0.51 0 0 $
+0.503 0 0 $
+0.497 0 0 $
+0.491 0 0 $
+0.484 0 0 $
+0.478 0 0 $
+0.471 0 0 $
+0.465 0 0 $
+454.84 605.361 454.84 591.25 axial
+popc
+newpath
+[5.36305 -1.08423 -0.365113 -6.61418 420.735 593.239] ellipse
+pushc
+eoclip newpath
+50 gradient
+0.424 0 0 $
+0.425 0 0 $
+0.426 0 0 $
+0.427 0 0 $
+0.428 0 0 $
+0.43 0 0 $
+0.431 0 0 $
+0.432 0 0 $
+0.433 0 0 $
+0.434 0 0 $
+0.435 0 0 $
+0.436 0 0 $
+0.437 0 0 $
+0.439 0 0 $
+0.44 0 0 $
+0.441 0 0 $
+0.442 0 0 $
+0.443 0 0 $
+0.444 0 0 $
+0.445 0 0 $
+0.446 0 0 $
+0.448 0 0 $
+0.449 0 0 $
+0.45 0 0 $
+0.451 0 0 $
+0.452 0 0 $
+0.453 0 0 $
+0.454 0 0 $
+0.463 0 0 $
+0.489 0 0 $
+0.515 0 0 $
+0.541 0 0 $
+0.566 0 0 $
+0.592 0 0 $
+0.618 0 0 $
+0.644 0 0 $
+0.67 0 0 $
+0.695 0 0 $
+0.721 0 0 $
+0.747 0 0 $
+0.773 0 0 $
+0.799 0 0 $
+0.824 0 0 $
+0.828 0 0 $
+!
+!
+!
+!
+!
+!
+419.172 595.338 11.2075 0 radial
+popc
+newpath
+newpath
+527.641 524.952 m
+522.96 522.791 l
+519.359 531.074 l
+511.437 522.791 l
+497.752 514.149 l
+519.359 514.869 l
+528.362 514.869 l
+538.805 516.309 l
+531.242 518.83 l
+535.924 522.791 l
+537.365 526.392 l
+534.124 526.753 l
+526.921 524.772 l
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.475 0 0 $
+0.474 0 0 $
+0.474 0 0 $
+0.473 0 0 $
+0.473 0 0 $
+0.472 0 0 $
+0.471 0 0 $
+0.471 0 0 $
+0.47 0 0 $
+0.47 0 0 $
+0.469 0 0 $
+0.468 0 0 $
+0.468 0 0 $
+0.467 0 0 $
+0.467 0 0 $
+0.466 0 0 $
+0.465 0 0 $
+0.465 0 0 $
+0.464 0 0 $
+0.464 0 0 $
+0.463 0 0 $
+0.462 0 0 $
+0.462 0 0 $
+0.461 0 0 $
+0.461 0 0 $
+0.46 0 0 $
+0.46 0 0 $
+0.459 0 0 $
+0.458 0 0 $
+0.458 0 0 $
+0.457 0 0 $
+0.457 0 0 $
+0.456 0 0 $
+0.455 0 0 $
+0.461 0 0 $
+0.476 0 0 $
+0.49 0 0 $
+0.504 0 0 $
+0.519 0 0 $
+0.533 0 0 $
+0.548 0 0 $
+0.562 0 0 $
+0.576 0 0 $
+0.591 0 0 $
+0.605 0 0 $
+0.619 0 0 $
+0.634 0 0 $
+0.648 0 0 $
+0.663 0 0 $
+0.677 0 0 $
+513.88 522.611 26.3224 0 radial
+popc
+newpath
+[8.05766 -0.851211 -0.548558 -5.1927 421.229 605.796] ellipse
+pushc
+eoclip newpath
+50 gradient
+0.424 0 0 $
+0.425 0 0 $
+0.426 0 0 $
+0.427 0 0 $
+0.428 0 0 $
+0.43 0 0 $
+0.431 0 0 $
+0.432 0 0 $
+0.433 0 0 $
+0.434 0 0 $
+0.435 0 0 $
+0.436 0 0 $
+0.437 0 0 $
+0.439 0 0 $
+0.44 0 0 $
+0.441 0 0 $
+0.442 0 0 $
+0.443 0 0 $
+0.444 0 0 $
+0.445 0 0 $
+0.446 0 0 $
+0.448 0 0 $
+0.449 0 0 $
+0.45 0 0 $
+0.451 0 0 $
+0.452 0 0 $
+0.453 0 0 $
+0.454 0 0 $
+0.463 0 0 $
+0.489 0 0 $
+0.515 0 0 $
+0.541 0 0 $
+0.566 0 0 $
+0.592 0 0 $
+0.618 0 0 $
+0.644 0 0 $
+0.67 0 0 $
+0.695 0 0 $
+0.721 0 0 $
+0.747 0 0 $
+0.773 0 0 $
+0.799 0 0 $
+0.824 0 0 $
+0.828 0 0 $
+!
+!
+!
+!
+!
+!
+418.881 607.444 12.5065 0 radial
+popc
+newpath
+[8.05766 -0.851211 -0.548558 -5.1927 417.831 599.877] ellipse
+pushc
+eoclip newpath
+50 gradient
+0.424 0 0 $
+0.425 0 0 $
+0.426 0 0 $
+0.427 0 0 $
+0.428 0 0 $
+0.43 0 0 $
+0.431 0 0 $
+0.432 0 0 $
+0.433 0 0 $
+0.434 0 0 $
+0.435 0 0 $
+0.436 0 0 $
+0.437 0 0 $
+0.439 0 0 $
+0.44 0 0 $
+0.441 0 0 $
+0.442 0 0 $
+0.443 0 0 $
+0.444 0 0 $
+0.445 0 0 $
+0.446 0 0 $
+0.448 0 0 $
+0.449 0 0 $
+0.45 0 0 $
+0.451 0 0 $
+0.452 0 0 $
+0.453 0 0 $
+0.454 0 0 $
+0.463 0 0 $
+0.489 0 0 $
+0.515 0 0 $
+0.541 0 0 $
+0.566 0 0 $
+0.592 0 0 $
+0.618 0 0 $
+0.644 0 0 $
+0.67 0 0 $
+0.695 0 0 $
+0.721 0 0 $
+0.747 0 0 $
+0.773 0 0 $
+0.799 0 0 $
+0.824 0 0 $
+0.828 0 0 $
+!
+!
+!
+!
+!
+!
+415.483 601.525 12.5065 0 radial
+popc
+newpath
+newpath
+416.727 544.758 m
+417.088 544.758 428.972 546.558 430.052 546.558 c
+431.132 546.558 434.733 546.919 436.173 548.719 c
+437.614 550.52 436.534 552.681 436.534 552.681 c
+436.534 552.681 434.733 558.082 435.093 558.442 c
+435.453 558.802 444.456 557.002 444.456 557.002 c
+444.456 557.002 450.938 557.362 452.378 555.561 c
+453.819 553.761 452.739 547.999 452.739 547.999 c
+452.739 547.999 450.218 544.037 449.858 544.037 c
+449.497 544.037 445.536 541.517 440.495 540.797 c
+435.453 540.077 435.814 542.598 431.132 541.157 c
+426.451 539.716 422.849 537.556 422.849 537.556 c
+422.849 537.556 417.448 544.758 417.448 544.758 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.556 0 0 $
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+0.564 0 0 $
+0.574 0 0 $
+0.585 0 0 $
+0.595 0 0 $
+0.606 0 0 $
+0.617 0 0 $
+0.627 0 0 $
+0.638 0 0 $
+0.648 0 0 $
+0.659 0 0 $
+0.669 0 0 $
+0.68 0 0 $
+0.691 0 0 $
+0.701 0 0 $
+0.712 0 0 $
+0.722 0 0 $
+0.733 0 0 $
+0.743 0 0 $
+0.754 0 0 $
+0.765 0 0 $
+0.775 0 0 $
+0.786 0 0 $
+0.796 0 0 $
+0.807 0 0 $
+0.817 0 0 $
+0.828 0 0 $
+432.761 549.418 23.5697 0 radial
+popc
+newpath
+newpath
+435.453 555.561 m
+435.453 555.921 434.373 558.442 434.373 558.442 c
+434.373 558.442 441.215 558.082 441.215 558.082 c
+441.215 558.082 446.977 557.002 446.977 557.002 c
+446.977 557.002 451.298 556.641 451.298 556.641 c
+451.298 556.641 452.739 553.761 452.739 553.761 c
+452.739 553.761 453.098 550.88 453.098 550.88 c
+453.098 550.88 446.617 552.32 446.256 552.681 c
+445.897 553.04 439.775 554.841 439.414 554.841 c
+439.055 554.841 435.453 557.002 435.453 557.002 c
+closepath
+0.434 0 0 rgb
+F
+newpath
+452.018 551.6 m
+452.018 551.6 453.098 550.88 452.018 547.639 c
+450.938 544.398 449.498 544.037 449.138 544.037 c
+448.777 544.037 446.256 542.237 446.256 542.237 c
+0.475 0 0 rgb
+1 w
+0 j
+0 J
+[] 0 d
+S
+newpath
+434.373 558.442 m
+434.373 558.442 434.733 558.082 435.814 555.201 c
+436.894 552.32 437.974 554.12 436.534 550.52 c
+435.093 546.919 434.733 547.278 434.733 547.278 c
+434.733 547.278 432.932 547.278 432.932 547.278 c
+S
+newpath
+475.065 553.401 m
+475.065 553.401 476.866 545.478 476.866 545.118 c
+476.866 544.758 479.747 539.356 479.387 539.356 c
+479.026 539.356 475.426 537.195 471.464 535.755 c
+467.503 534.315 462.462 531.794 459.221 531.434 c
+455.98 531.074 446.256 531.794 446.256 531.794 c
+446.256 531.794 445.897 535.395 441.575 537.916 c
+437.254 540.437 428.972 541.517 428.972 541.517 c
+428.972 541.517 439.775 543.678 439.775 543.678 c
+439.775 543.678 448.777 545.478 448.777 545.478 c
+448.777 545.478 450.218 554.481 450.218 554.481 c
+450.218 554.481 455.619 555.561 455.98 555.561 c
+456.339 555.561 467.863 555.921 468.223 555.921 c
+468.584 555.921 474.345 554.12 474.345 554.12 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.556 0 0 $
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+!
+0.564 0 0 $
+0.574 0 0 $
+0.585 0 0 $
+0.595 0 0 $
+0.606 0 0 $
+0.617 0 0 $
+0.627 0 0 $
+0.638 0 0 $
+0.648 0 0 $
+0.659 0 0 $
+0.669 0 0 $
+0.68 0 0 $
+0.691 0 0 $
+0.701 0 0 $
+0.712 0 0 $
+0.722 0 0 $
+0.733 0 0 $
+0.743 0 0 $
+0.754 0 0 $
+0.765 0 0 $
+0.775 0 0 $
+0.786 0 0 $
+0.796 0 0 $
+0.807 0 0 $
+0.817 0 0 $
+0.828 0 0 $
+451.192 545.266 31.4774 0 radial
+popc
+newpath
+newpath
+453.098 555.561 m
+463.542 559.162 l
+473.265 559.523 l
+475.785 553.401 l
+476.866 547.639 l
+477.586 543.318 l
+474.705 546.198 l
+467.863 549.079 l
+458.14 550.88 l
+453.098 552.32 l
+450.938 554.481 l
+452.739 555.921 l
+closepath
+0.434 0 0 rgb
+F
+453.098 555.561 m
+463.542 559.162 l
+473.265 559.523 l
+475.785 553.401 l
+476.866 547.639 l
+477.586 543.318 l
+474.705 546.198 l
+467.863 549.079 l
+458.14 550.88 l
+453.098 552.32 l
+450.938 554.481 l
+452.739 555.921 l
+0.475 0 0 rgb
+1 w
+0 j
+0 J
+[] 0 d
+S
+[15.1246 0 0 -7.74233 413.127 537.735] ellipse
+pushc
+eoclip newpath
+50 gradient
+0.576 0.576 0.576 $
+0.585 0.585 0.585 $
+0.593 0.593 0.593 $
+0.602 0.602 0.602 $
+0.611 0.611 0.611 $
+0.619 0.619 0.619 $
+0.628 0.628 0.628 $
+0.637 0.637 0.637 $
+0.645 0.645 0.645 $
+0.654 0.654 0.654 $
+0.663 0.663 0.663 $
+0.671 0.671 0.671 $
+0.68 0.68 0.68 $
+0.688 0.688 0.688 $
+0.697 0.697 0.697 $
+0.706 0.706 0.706 $
+0.714 0.714 0.714 $
+0.723 0.723 0.723 $
+0.732 0.732 0.732 $
+0.74 0.74 0.74 $
+0.749 0.749 0.749 $
+0.758 0.758 0.758 $
+0.766 0.766 0.766 $
+0.775 0.775 0.775 $
+0.784 0.784 0.784 $
+0.792 0.792 0.792 $
+0.801 0.801 0.801 $
+0.81 0.81 0.81 $
+0.818 0.818 0.818 $
+0.827 0.827 0.827 $
+0.836 0.836 0.836 $
+0.844 0.844 0.844 $
+0.853 0.853 0.853 $
+0.862 0.862 0.862 $
+0.87 0.87 0.87 $
+0.879 0.879 0.879 $
+0.888 0.888 0.888 $
+0.896 0.896 0.896 $
+0.905 0.905 0.905 $
+0.913 0.913 0.913 $
+0.922 0.922 0.922 $
+0.931 0.931 0.931 $
+0.939 0.939 0.939 $
+0.948 0.948 0.948 $
+0.957 0.957 0.957 $
+0.965 0.965 0.965 $
+0.974 0.974 0.974 $
+0.983 0.983 0.983 $
+0.991 0.991 0.991 $
+1 1 1 $
+406.645 540.058 23.8358 0 radial
+popc
+newpath
+newpath
+401.536 541.99 m
+401.536 541.99 399.555 541.45 399.376 541.27 c
+399.195 541.09 397.935 538.569 397.935 538.569 c
+397.935 538.569 402.976 535.328 402.976 535.328 c
+402.976 535.328 407.118 532.987 410.539 532.627 c
+413.96 532.267 417.021 531.907 417.021 531.907 c
+417.021 531.907 417.201 535.148 416.66 535.148 c
+416.12 535.148 410.358 536.048 410.179 536.048 c
+409.999 536.048 408.018 535.868 404.417 538.749 c
+400.816 541.63 402.256 541.27 402.076 541.27 c
+closepath
+0.596 0.596 0.596 rgb
+F
+[15.1246 0 0 -7.74233 430.975 533.257] ellipse
+pushc
+eoclip newpath
+50 gradient
+0.576 0.576 0.576 $
+0.585 0.585 0.585 $
+0.593 0.593 0.593 $
+0.602 0.602 0.602 $
+0.611 0.611 0.611 $
+0.619 0.619 0.619 $
+0.628 0.628 0.628 $
+0.637 0.637 0.637 $
+0.645 0.645 0.645 $
+0.654 0.654 0.654 $
+0.663 0.663 0.663 $
+0.671 0.671 0.671 $
+0.68 0.68 0.68 $
+0.688 0.688 0.688 $
+0.697 0.697 0.697 $
+0.706 0.706 0.706 $
+0.714 0.714 0.714 $
+0.723 0.723 0.723 $
+0.732 0.732 0.732 $
+0.74 0.74 0.74 $
+0.749 0.749 0.749 $
+0.758 0.758 0.758 $
+0.766 0.766 0.766 $
+0.775 0.775 0.775 $
+0.784 0.784 0.784 $
+0.792 0.792 0.792 $
+0.801 0.801 0.801 $
+0.81 0.81 0.81 $
+0.818 0.818 0.818 $
+0.827 0.827 0.827 $
+0.836 0.836 0.836 $
+0.844 0.844 0.844 $
+0.853 0.853 0.853 $
+0.862 0.862 0.862 $
+0.87 0.87 0.87 $
+0.879 0.879 0.879 $
+0.888 0.888 0.888 $
+0.896 0.896 0.896 $
+0.905 0.905 0.905 $
+0.913 0.913 0.913 $
+0.922 0.922 0.922 $
+0.931 0.931 0.931 $
+0.939 0.939 0.939 $
+0.948 0.948 0.948 $
+0.957 0.957 0.957 $
+0.965 0.965 0.965 $
+0.974 0.974 0.974 $
+0.983 0.983 0.983 $
+0.991 0.991 0.991 $
+1 1 1 $
+424.493 535.58 23.8359 0 radial
+popc
+newpath
+newpath
+443.015 533.954 m
+443.015 533.954 452.018 532.874 461.742 533.954 c
+471.464 535.035 479.026 538.996 479.026 538.996 c
+479.026 538.996 480.467 531.434 480.467 531.434 c
+480.467 531.434 469.664 527.473 462.101 526.392 c
+454.539 525.312 437.974 526.032 437.974 526.032 c
+437.974 526.032 435.093 526.392 435.093 526.392 c
+435.093 526.392 442.295 533.954 442.295 533.954 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.576 0.576 0.576 $
+0.585 0.585 0.585 $
+0.593 0.593 0.593 $
+0.602 0.602 0.602 $
+0.611 0.611 0.611 $
+0.619 0.619 0.619 $
+0.628 0.628 0.628 $
+0.637 0.637 0.637 $
+0.645 0.645 0.645 $
+0.654 0.654 0.654 $
+0.663 0.663 0.663 $
+0.671 0.671 0.671 $
+0.68 0.68 0.68 $
+0.688 0.688 0.688 $
+0.697 0.697 0.697 $
+0.706 0.706 0.706 $
+0.714 0.714 0.714 $
+0.723 0.723 0.723 $
+0.732 0.732 0.732 $
+0.74 0.74 0.74 $
+0.749 0.749 0.749 $
+0.758 0.758 0.758 $
+0.766 0.766 0.766 $
+0.775 0.775 0.775 $
+0.784 0.784 0.784 $
+0.792 0.792 0.792 $
+0.801 0.801 0.801 $
+0.81 0.81 0.81 $
+0.818 0.818 0.818 $
+0.827 0.827 0.827 $
+0.836 0.836 0.836 $
+0.844 0.844 0.844 $
+0.853 0.853 0.853 $
+0.862 0.862 0.862 $
+0.87 0.87 0.87 $
+0.879 0.879 0.879 $
+0.888 0.888 0.888 $
+0.896 0.896 0.896 $
+0.905 0.905 0.905 $
+0.913 0.913 0.913 $
+0.922 0.922 0.922 $
+0.931 0.931 0.931 $
+0.939 0.939 0.939 $
+0.948 0.948 0.948 $
+0.957 0.957 0.957 $
+0.965 0.965 0.965 $
+0.974 0.974 0.974 $
+0.983 0.983 0.983 $
+0.991 0.991 0.991 $
+1 1 1 $
+455.432 543.354 460.128 521.439 axial
+popc
+newpath
+newpath
+432.212 546.558 m
+435.814 544.758 l
+0.768 0.768 0.768 rgb
+1 w
+0 j
+0 J
+[] 0 d
+S
+newpath
+435.093 548.359 m
+439.055 545.838 l
+S
+newpath
+444.456 544.037 m
+449.497 542.598 l
+S
+newpath
+448.057 545.838 m
+451.298 544.758 l
+S
+newpath
+428.972 525.492 m
+429.331 525.852 432.572 531.794 432.572 531.794 c
+432.572 531.794 443.015 530.353 443.015 530.353 c
+443.015 530.353 451.838 530.173 452.558 529.813 c
+453.279 529.453 468.943 532.154 469.304 532.515 c
+469.664 532.874 479.387 537.195 479.387 537.195 c
+479.387 537.195 481.547 531.254 481.187 531.254 c
+480.827 531.254 480.467 529.813 465.342 527.112 c
+450.218 524.412 450.938 525.132 442.656 525.492 c
+434.373 525.852 428.611 525.672 428.611 525.672 c
+closepath
+0.596 0.596 0.596 rgb
+F
+newpath
+420.058 538.366 m
+420.058 538.366 418.078 537.826 417.898 537.646 c
+417.718 537.465 416.457 534.945 416.457 534.945 c
+416.457 534.945 421.499 531.704 421.499 531.704 c
+421.499 531.704 425.64 529.363 429.061 529.003 c
+432.483 528.643 433.563 529.543 433.563 529.543 c
+433.563 529.543 434.103 531.884 433.563 531.884 c
+433.023 531.884 428.881 532.424 428.701 532.424 c
+428.521 532.424 426.541 532.244 422.94 535.125 c
+419.338 538.006 420.779 537.646 420.599 537.646 c
+closepath
+F
+newpath
+426.451 622.542 m
+426.451 622.542 433.112 618.58 433.833 617.32 c
+434.553 616.06 439.414 613.179 442.295 613.179 c
+445.176 613.179 451.298 615.7 451.298 615.7 c
+451.298 615.7 461.742 619.301 461.742 619.301 c
+461.742 619.301 455.799 618.761 450.038 616.96 c
+444.276 615.159 444.816 615.339 441.935 615.339 c
+439.055 615.339 434.013 619.301 433.653 619.301 c
+433.293 619.301 426.451 622.542 426.451 622.542 c
+closepath
+pushc
+eoclip newpath
+50 gradient
+0.616 0 0 $
+0.611 0 0 $
+0.606 0 0 $
+0.602 0 0 $
+0.597 0 0 $
+0.592 0 0 $
+0.587 0 0 $
+0.582 0 0 $
+0.578 0 0 $
+0.573 0 0 $
+0.568 0 0 $
+0.563 0 0 $
+0.558 0 0 $
+0.554 0 0 $
+0.549 0 0 $
+0.544 0 0 $
+0.539 0 0 $
+0.534 0 0 $
+0.53 0 0 $
+0.525 0 0 $
+0.52 0 0 $
+0.515 0 0 $
+0.51 0 0 $
+0.506 0 0 $
+0.501 0 0 $
+0.496 0 0 $
+0.491 0 0 $
+0.486 0 0 $
+0.482 0 0 $
+0.477 0 0 $
+0.472 0 0 $
+0.467 0 0 $
+0.463 0 0 $
+0.458 0 0 $
+0.455 0 0 $
+0.456 0 0 $
+0.457 0 0 $
+0.457 0 0 $
+0.458 0 0 $
+0.459 0 0 $
+0.459 0 0 $
+0.46 0 0 $
+0.46 0 0 $
+0.461 0 0 $
+0.462 0 0 $
+0.462 0 0 $
+0.463 0 0 $
+0.464 0 0 $
+0.464 0 0 $
+0.465 0 0 $
+444.096 617.86 18.256 0 radial
+popc
+newpath
+newpath
+246.446 791.099 m
+246.263 653.969 l
+257.252 653.969 l
+266.043 663.649 l
+266.043 779.806 l
+259.45 790.292 l
+246.263 790.292 l
+closepath
+1 1 1 rgb
+F
+newpath
+338.281 563.853 m
+261.027 609.375 l
+271.99 609.375 l
+286.201 606.162 l
+351.486 567.602 l
+350.801 564.121 l
+337.645 564.121 l
+closepath
+F
+newpath
+71.1751 794.729 m
+71.1751 739.474 l
+83.6291 739.474 l
+87.292 751.573 l
+86.9257 784.646 l
+82.5302 794.326 l
+71.5414 794.326 l
+closepath
+F
+newpath
+165.457 562.648 m
+134.401 580.991 l
+146.827 580.991 l
+157.281 576.974 l
+175.504 565.995 l
+176.559 562.782 l
+165.596 562.782 l
+closepath
+F
+newpath
+71.1751 705.191 m
+71.1751 649.936 l
+83.6291 649.936 l
+87.292 662.036 l
+86.9257 695.108 l
+82.5302 704.788 l
+71.5414 704.788 l
+closepath
+F
+newpath
+115.134 592.371 m
+84.0782 610.714 l
+96.5032 610.714 l
+106.958 606.698 l
+125.181 595.719 l
+126.236 592.505 l
+115.272 592.505 l
+closepath
+F
+showpage
+end
+%%Trailer
+cleartomark countdictstack exch sub { end } repeat restore
+%%EOF
diff --git a/share/examples/BSD_daemon/eps.patch b/share/examples/BSD_daemon/eps.patch
new file mode 100644
index 000000000000..5f23cb69ef9c
--- /dev/null
+++ b/share/examples/BSD_daemon/eps.patch
@@ -0,0 +1,35 @@
+--- beastie.eps.ref Sun Feb 11 22:46:59 2001
++++ beastie.eps Sun Feb 11 23:01:43 2001
+@@ -19,6 +19,23 @@
+ %
+ /$F2psDict 200 dict def
+ $F2psDict begin
++
++% This controls the linethickness. I think large posters look better if
++% you use a value of 2. Small daemons looks better with a value of 1.
++/linethickness 1 def
++
++% If you want to fiddle the colors:
++% col0 below is black (the lines)
++% col3 below is cyan (the shoelaces)
++% col7 below is white (eyes, shoes)
++% col13 below is green (the shooes)
++% col20 below is red (the daemon)
++% col31 below is gold (the pitchfork)
++
++% This sets round ends on the lines, this looks better than sharp edges
++% but I have not found a way to convince xfig to do this.
++1 setlinecap
++
+ $F2psDict /mtrx matrix put
+ /col-1 {0 setgray} bind def
+ /col0 {0.000 0.000 0.000 srgb} bind def
+@@ -74,7 +91,7 @@
+ /sh {show} bind def
+ /slc {setlinecap} bind def
+ /slj {setlinejoin} bind def
+-/slw {setlinewidth} bind def
++/slw {linethickness mul setlinewidth} bind def
+ /srgb {setrgbcolor} bind def
+ /rot {rotate} bind def
+ /sc {scale} bind def
diff --git a/share/examples/BSD_daemon/poster.sh b/share/examples/BSD_daemon/poster.sh
new file mode 100644
index 000000000000..7465c243b769
--- /dev/null
+++ b/share/examples/BSD_daemon/poster.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# "THE BEER-WARE LICENSE" (Revision 42):
+# <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+# can do whatever you want with this stuff. If we meet some day, and you think
+# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+# ----------------------------------------------------------------------------
+#
+#
+
+echo '%!'
+echo '/beastie {'
+cat beastie.eps
+echo '} def'
+cat FreeBSD.pfa
+
+echo '
+
+/mm {25.4 div 72 mul} def
+/FreeBSD findfont 120 scalefont setfont
+/center 210 mm 2 div def
+/top 297 mm def
+/cshow { dup stringwidth pop 2 div neg 0 rmoveto show } def
+
+% "FreeBSD" across the top.
+% 691 is "top - height of caps - (left - X("F"))"
+center 691 moveto
+(FreeBSD) cshow
+
+% Put beastie in the center
+/sc 1.25 def
+center 125 moveto
+384 sc mul 2 div neg 0 rmoveto
+gsave currentpoint translate sc sc scale beastie grestore
+
+% A box for the bottom text
+gsave
+10 30 moveto
+210 mm 20 sub 0 rlineto
+0 70 rlineto
+210 mm 20 sub neg 0 rlineto
+closepath
+.7 .7 .9 setrgbcolor
+fill
+grestore
+
+% Bottom text
+center 90 moveto
+/FreeBSD findfont 50 scalefont setfont
+
+center 50 moveto
+(https://www.FreeBSD.org) cshow
+
+% Do not forget Kirks copyright string.
+10 105 moveto
+/Times-Roman findfont 8 scalefont setfont
+(BSD Daemon ) show
+/Symbol findfont 8 scalefont setfont
+(\343 ) show
+/Times-Roman findfont 8 scalefont setfont
+(Copyright 1988 by Marshall Kirk McKusick. All Rights Reserved.) show
+
+showpage
+'
diff --git a/share/examples/FreeBSD_version/FreeBSD_version.c b/share/examples/FreeBSD_version/FreeBSD_version.c
new file mode 100644
index 000000000000..e3f5600a857f
--- /dev/null
+++ b/share/examples/FreeBSD_version/FreeBSD_version.c
@@ -0,0 +1,20 @@
+#if __FreeBSD__ == 0 /* 1.0 did not define __FreeBSD__ */
+#define __FreeBSD_version 199401
+#elif __FreeBSD__ == 1 /* 1.1 defined it to be 1 */
+#define __FreeBSD_version 199405
+#else /* 2.0 and higher define it to be 2 */
+#include <osreldate.h> /* and this works */
+#endif
+#include <stdio.h>
+#include <unistd.h>
+
+int
+main(void) {
+ printf("Compilation release date: %d\n", __FreeBSD_version);
+#if __FreeBSD_version >= 199408
+ printf("Execution environment release date: %d\n", getosreldate());
+#else
+ printf("Execution environment release date: can't tell\n");
+#endif
+ return (0);
+}
diff --git a/share/examples/FreeBSD_version/Makefile b/share/examples/FreeBSD_version/Makefile
new file mode 100644
index 000000000000..13d60978e868
--- /dev/null
+++ b/share/examples/FreeBSD_version/Makefile
@@ -0,0 +1,9 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/${PROG}
+PROG= FreeBSD_version
+MAN=
+
+install:
+
+.include <bsd.prog.mk>
diff --git a/share/examples/FreeBSD_version/README b/share/examples/FreeBSD_version/README
new file mode 100644
index 000000000000..acf9eb1a963f
--- /dev/null
+++ b/share/examples/FreeBSD_version/README
@@ -0,0 +1,4 @@
+This is an example of how to determine the version of FreeBSD that
+a program was compiled on, and maybe running on (if 2.0 or better).
+
+This program is in the public domain.
diff --git a/share/examples/Makefile b/share/examples/Makefile
new file mode 100644
index 000000000000..0425e36c1cf5
--- /dev/null
+++ b/share/examples/Makefile
@@ -0,0 +1,419 @@
+#
+# Doing a make install builds /usr/share/examples
+
+.include <src.opts.mk>
+
+PACKAGE=examples
+FILESDIR= ${SHAREDIR}/examples
+
+LDIRS= BSD_daemon \
+ FreeBSD_version \
+ bootforth \
+ csh \
+ drivers \
+ etc \
+ find_interface \
+ flua \
+ indent \
+ ipfw \
+ jails \
+ kld \
+ libvgl \
+ mdoc \
+ netgraph \
+ perfmon \
+ ppi \
+ ppp \
+ printing \
+ ses \
+ scsi_target \
+ sound \
+ sunrpc \
+ ypldap
+
+
+SE_DIRS+= BSD_daemon
+SE_BSD_DAEMON= \
+ FreeBSD.pfa \
+ README \
+ beastie.eps \
+ beastie.fig \
+ eps.patch \
+ poster.sh
+
+.if ${MACHINE_CPUARCH} == "amd64"
+.if ${MK_BHYVE} != "no"
+LDIRS+= bhyve
+SE_DIRS+= bhyve
+SE_BHYVEPACKAGE=bhyve
+SE_BHYVE= vmrun.sh
+PACKAGE_bhyve/vmrun.sh= bhyve
+.endif
+.endif
+
+SE_DIRS+= FreeBSD_version
+SE_FREEBSD_VERSION= \
+ FreeBSD_version.c \
+ Makefile \
+ README
+
+SE_DIRS+= bootforth
+SE_BOOTFORTH_PACKAGE=bootloader
+SE_BOOTFORTH= \
+ README \
+ boot.4th \
+ frames.4th \
+ loader.rc \
+ menu.4th \
+ menuconf.4th \
+ screen.4th
+
+SE_DIRS+= csh
+SE_CSHPACKAGE= csh
+SE_CSH= dot.cshrc
+
+SE_DIRS+= drivers
+SE_DRIVERS= \
+ README \
+ make_device_driver.sh \
+ make_pseudo_driver.sh
+
+SE_DIRS+= etc
+SE_ETC= \
+ README.examples \
+ bsd-style-copyright \
+ make.conf
+
+SE_DIRS+= find_interface
+SE_FIND_INTERFACE= \
+ Makefile \
+ README \
+ find_interface.c
+
+SE_DIRS+= flua
+SE_FLUA= libjail.lua
+
+SE_DIRS+= indent
+SE_INDENT= indent.pro
+
+.if ${MK_IPFILTER} != "no"
+SUBDIR+= ipfilter
+.endif
+
+SE_DIRS+= ipfw
+SE_IPFWPACKAGE= ipfw
+SE_IPFW= change_rules.sh
+
+SE_DIRS+= jails
+SE_JAILPACKAGE= jail
+SE_JAILS= \
+ README \
+ VIMAGE \
+ jail.xxx.conf \
+ jib \
+ jng \
+ rc.conf.jails \
+ rcjail.xxx.conf
+
+SE_DIRS+= kld
+SE_KLD= Makefile
+
+SE_DIRS+= kld/cdev
+SE_KLD_CDEV= \
+ Makefile \
+ README \
+
+SE_DIRS+= kld/cdev/module
+SE_KLD_CDEV_MODULE= \
+ Makefile \
+ cdev.c \
+ cdev.h \
+ cdevmod.c
+
+SE_DIRS+= kld/cdev/test
+SE_KLD_CDEV_TEST= \
+ Makefile \
+ testcdev.c
+
+SE_DIRS+= kld/dyn_sysctl
+SE_KLD_DYN_SYSCTL= \
+ Makefile \
+ README \
+ dyn_sysctl.c
+
+SE_DIRS+= kld/firmware
+SE_KLD_FIRMWARE= \
+ Makefile \
+ README
+
+SE_DIRS+= kld/firmware/fwconsumer
+SE_KLD_FIRMWARE_FWCONSUMER= \
+ Makefile \
+ fw_consumer.c
+
+SE_DIRS+= kld/firmware/fwimage
+SE_KLD_FIRMWARE_FWIMAGE= \
+ Makefile \
+ firmware.img.uu
+
+SE_DIRS+= kld/khelp
+SE_KLD_KHELP= \
+ Makefile \
+ README \
+ h_example.c
+
+SE_DIRS+= kld/syscall
+SE_KLD_SYSCALL= Makefile
+
+SE_DIRS+= kld/syscall/module
+SE_KLD_SYSCALL_MODULE= \
+ Makefile \
+ syscall.c
+
+SE_DIRS+= kld/syscall/test
+SE_KLD_SYSCALL_TEST= \
+ Makefile \
+ call.c
+
+SE_DIRS+= libvgl
+SE_LIBVGL= \
+ Makefile \
+ demo.c
+
+SE_DIRS+= mdoc
+SE_MDOC= \
+ POSIX-copyright \
+ deshallify.sh \
+ example.1 \
+ example.3 \
+ example.4 \
+ example.9
+
+SE_DIRS+= netgraph
+SE_NETGRAPH= \
+ ether.bridge \
+ frame_relay \
+ ngctl \
+ raw \
+ udp.tunnel \
+ virtual.chain \
+ virtual.lan \
+
+SE_DIRS+= perfmon
+SE_PERFMON= \
+ Makefile \
+ README \
+ perfmon.c \
+
+.if ${MK_PF} != "no"
+SE_DIRS+= pf
+.if ${MK_STAGING} == "no"
+SE_PFPACKAGE= pf
+SE_PF= \
+ ackpri \
+ faq-example1 \
+ faq-example2 \
+ faq-example3 \
+ pf.conf \
+ queue1 \
+ queue2 \
+ queue3 \
+ queue4 \
+ spamd
+.endif
+.endif
+
+SE_DIRS+= ppi
+SE_PPI= \
+ Makefile \
+ ppilcd.c
+
+SE_DIRS+= ppp
+SE_PPPPACKAGE= ppp
+SE_PPP= \
+ chap-auth \
+ login-auth \
+ ppp.conf.sample \
+ ppp.conf.span-isp \
+ ppp.conf.span-isp.working \
+ ppp.linkdown.sample \
+ ppp.linkdown.span-isp \
+ ppp.linkdown.span-isp.working \
+ ppp.linkup.sample \
+ ppp.linkup.span-isp \
+ ppp.linkup.span-isp.working \
+ ppp.secret.sample \
+ ppp.secret.span-isp \
+ ppp.secret.span-isp.working
+
+SE_DIRS+= printing
+SE_PRINTINGPACKAGE=lp
+SE_PRINTING= \
+ diablo-if-net \
+ hpdf \
+ hpif \
+ hpof \
+ hprf \
+ hpvf \
+ if-simple \
+ if-simpleX \
+ ifhp \
+ make-ps-header \
+ netprint \
+ psdf \
+ psdfX \
+ psif \
+ pstf \
+ pstfX
+
+SE_DIRS+= ses
+SE_SES= \
+ Makefile \
+ Makefile.inc
+
+SE_DIRS+= ses/getencstat
+SE_SES_GETENCSTAT= \
+ Makefile \
+ getencstat.0
+
+SE_DIRS+= ses/sesd
+SE_SES_SESD= \
+ Makefile \
+ sesd.0
+
+SE_DIRS+= ses/setencstat
+SE_SES_SETENCSTAT= \
+ Makefile \
+ setencstat.0
+
+SE_DIRS+= ses/setobjstat
+SE_SES_SETOBJSTAT= \
+ Makefile \
+ setobjstat.0
+
+SE_DIRS+= ses/srcs
+SE_SES_SRCS= \
+ chpmon.c \
+ eltsub.c \
+ eltsub.h \
+ getencstat.c \
+ getnobj.c \
+ getobjmap.c \
+ getobjstat.c \
+ inienc.c \
+ sesd.c \
+ setencstat.c \
+ setobjstat.c
+
+SE_DIRS+= scsi_target
+SE_SCSI_TARGET= \
+ Makefile \
+ scsi_target.c \
+ scsi_target.h \
+ scsi_target.8 \
+ scsi_cmds.c
+
+SE_DIRS+= sound
+SE_SOUND= \
+ basic.c \
+ ossinit.h \
+ ossmidi.h \
+ midi.c \
+ README
+
+SE_DIRS+= sunrpc
+SE_SUNRPC= Makefile
+
+SE_DIRS+= sunrpc/dir
+SE_SUNRPC_DIR= \
+ Makefile \
+ dir.x \
+ dir_proc.c \
+ rls.c
+
+SE_DIRS+= sunrpc/msg
+SE_SUNRPC_MSG= \
+ Makefile \
+ msg.x \
+ msg_proc.c \
+ printmsg.c \
+ rprintmsg.c
+
+SE_DIRS+= sunrpc/sort
+SE_SUNRPC_SORT= \
+ Makefile \
+ rsort.c \
+ sort.x \
+ sort_proc.c
+
+.if ${MK_EFI} != "no"
+LDIRS+= uefisign
+SE_DIRS+= uefisign
+SE_UEFISIGN= uefikeys
+SE_UEFISIGNPACKAGE=efi-tools
+.endif
+
+SE_DIRS+= ypldap
+SE_YPLDAP= ypldap.conf
+SE_YPLDAPPACKAGE=yp
+
+.if ${MK_HAST} != "no"
+LDIRS+= hast
+SE_HASTPACKAGE= hast
+SE_DIRS+= hast
+SE_HAST= ucarp.sh \
+ ucarp_down.sh \
+ ucarp_up.sh \
+ vip-down.sh \
+ vip-up.sh
+.endif
+
+.if ${MK_USB} != "no"
+LDIRS+= libusb20
+SE_DIRS+= libusb20
+SE_LIBUSB20= \
+ Makefile \
+ README \
+ util.c \
+ util.h \
+ bulk.c \
+ control.c
+.endif
+
+
+# Setup the FILES_GROUPS for all DIRS variables above.
+# The variables are prefixed by 'SE_' to prevent variable collision in
+# other parts of the system
+.for d in ${SE_DIRS}
+.for f in ${SE_${d:tu:C/\//_/g}}
+SER_${d:tu:C/\//_/g}+= ${d}/${f}
+.endfor
+FILESGROUPS+= SER_${d:tu:C/\//_/g}
+SER_${d:tu:C/\//_/g}DIR+= ${SHAREDIR}/examples/${d}
+.if ${SE_${d:tu:C/\//_/g}PACKAGE:U} != ""
+SER_${d:tu:C/\//_/g}PACKAGE= ${SE_${d:tu:C/\//_/g}PACKAGE}
+.else
+SER_${d:tu:C/\//_/g}PACKAGE= examples
+.endif
+.endfor
+
+BINDIR= ${SHAREDIR}/examples
+
+beforeinstall: copies
+META_TARGETS+= copies
+
+copies:
+.for i in ${LDIRS}
+ if [ -L ${DESTDIR}${BINDIR}/$i ]; then \
+ rm -f ${DESTDIR}${BINDIR}/$i; \
+ fi
+.endfor
+
+SUBDIR+= smbfs
+
+HAS_TESTS=
+SUBDIR.${MK_TESTS}+= tests
+
+SUBDIR_PARALLEL=
+
+.include <bsd.prog.mk>
diff --git a/share/examples/Makefile.depend b/share/examples/Makefile.depend
new file mode 100644
index 000000000000..11aba52f82cf
--- /dev/null
+++ b/share/examples/Makefile.depend
@@ -0,0 +1,10 @@
+# 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/share/examples/bhyve/vmrun.sh b/share/examples/bhyve/vmrun.sh
new file mode 100755
index 000000000000..323d8e22a041
--- /dev/null
+++ b/share/examples/bhyve/vmrun.sh
@@ -0,0 +1,410 @@
+#!/bin/sh
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2013 NetApp, Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY 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.
+#
+#
+
+LOADER=/usr/sbin/bhyveload
+BHYVECTL=/usr/sbin/bhyvectl
+FBSDRUN=/usr/sbin/bhyve
+
+DEFAULT_MEMSIZE=512M
+DEFAULT_CPUS=2
+DEFAULT_TAPDEV=tap0
+DEFAULT_CONSOLE=stdio
+
+DEFAULT_NIC=virtio-net
+DEFAULT_DISK=virtio-blk
+DEFAULT_VIRTIO_DISK="./diskdev"
+DEFAULT_ISOFILE="./release.iso"
+
+DEFAULT_VNCHOST="127.0.0.1"
+DEFAULT_VNCPORT=5900
+DEFAULT_VNCSIZE="w=1024,h=768"
+
+errmsg() {
+ echo "*** $1"
+}
+
+usage() {
+ local msg=$1
+
+ echo "Usage: vmrun.sh [-aAEhiTuvw] [-c <CPUs>] [-C <console>]" \
+ "[-d <disk file>]"
+ echo " [-e <name=value>] [-f <path of firmware>]" \
+ "[-F <size>]"
+ echo " [-G [w][address:]port] [-H <directory>]"
+ echo " [-I <location of installation iso>] [-l <loader>]"
+ echo " [-L <VNC IP for UEFI framebuffer>]"
+ echo " [-m <memsize>]" \
+ "[-n <network adapter emulation type>]"
+ echo " [-p <pcidev|bus/slot/func>]"
+ echo " [-P <port>] [-t <tapdev>] <vmname>"
+ echo ""
+ echo " -h: display this help message"
+ echo " -a: force memory mapped local APIC access"
+ echo " -A: use AHCI disk emulation instead of ${DEFAULT_DISK}"
+ echo " -c: number of virtual cpus (default: ${DEFAULT_CPUS})"
+ echo " -C: console device (default: ${DEFAULT_CONSOLE})"
+ echo " -d: virtio diskdev file (default: ${DEFAULT_VIRTIO_DISK})"
+ echo " -e: set FreeBSD loader environment variable"
+ echo " -E: Use UEFI mode"
+ echo " -f: Use a specific UEFI firmware"
+ echo " -F: Use a custom UEFI GOP framebuffer size" \
+ "(default: ${DEFAULT_VNCSIZE})"
+ echo " -G: bind the GDB stub to the specified address"
+ echo " -H: host filesystem to export to the loader"
+ echo " -i: force boot of the Installation CDROM image"
+ echo " -I: Installation CDROM image location" \
+ "(default: ${DEFAULT_ISOFILE})"
+ echo " -l: the OS loader to use (default: /boot/userboot.so)"
+ echo " -L: IP address for UEFI GOP VNC server" \
+ "(default: ${DEFAULT_VNCHOST})"
+ echo " -m: memory size (default: ${DEFAULT_MEMSIZE})"
+ echo " -n: network adapter emulation type" \
+ "(default: ${DEFAULT_NIC})"
+ echo " -p: pass-through a host PCI device (e.g ppt0 or" \
+ "bus/slot/func)"
+ echo " -P: UEFI GOP VNC port (default: ${DEFAULT_VNCPORT})"
+ echo " -t: tap device for virtio-net (default: $DEFAULT_TAPDEV)"
+ echo " -T: Enable tablet device (for UEFI GOP)"
+ echo " -u: RTC keeps UTC time"
+ echo " -v: Wait for VNC client connection before booting VM"
+ echo " -w: ignore unimplemented MSRs"
+ echo ""
+ [ -n "$msg" ] && errmsg "$msg"
+ exit 1
+}
+
+if [ `id -u` -ne 0 ]; then
+ errmsg "This script must be executed with superuser privileges"
+ exit 1
+fi
+
+kldstat -n vmm > /dev/null 2>&1
+if [ $? -ne 0 ]; then
+ errmsg "vmm.ko is not loaded"
+ exit 1
+fi
+
+force_install=0
+isofile=${DEFAULT_ISOFILE}
+memsize=${DEFAULT_MEMSIZE}
+console=${DEFAULT_CONSOLE}
+cpus=${DEFAULT_CPUS}
+nic=${DEFAULT_NIC}
+tap_total=0
+disk_total=0
+disk_emulation=${DEFAULT_DISK}
+loader_opt=""
+bhyverun_opt="-H -A -P"
+pass_total=0
+
+# EFI-specific options
+efi_mode=0
+efi_firmware="/usr/local/share/uefi-firmware/BHYVE_UEFI.fd"
+vncwait=""
+vnchost=${DEFAULT_VNCHOST}
+vncport=${DEFAULT_VNCPORT}
+vncsize=${DEFAULT_VNCSIZE}
+tablet=""
+
+while getopts aAc:C:d:e:Ef:F:G:hH:iI:l:L:m:n:p:P:t:Tuvw c ; do
+ case $c in
+ a)
+ bhyverun_opt="${bhyverun_opt} -a"
+ ;;
+ A)
+ disk_emulation="ahci-hd"
+ ;;
+ c)
+ cpus=${OPTARG}
+ ;;
+ C)
+ console=${OPTARG}
+ ;;
+ d)
+ disk_dev=${OPTARG%%,*}
+ disk_opts=${OPTARG#${disk_dev}}
+ eval "disk_dev${disk_total}=\"${disk_dev}\""
+ eval "disk_opts${disk_total}=\"${disk_opts}\""
+ disk_total=$(($disk_total + 1))
+ ;;
+ e)
+ loader_opt="${loader_opt} -e ${OPTARG}"
+ ;;
+ E)
+ efi_mode=1
+ ;;
+ f)
+ efi_firmware="${OPTARG}"
+ ;;
+ F)
+ vncsize="${OPTARG}"
+ ;;
+ G)
+ bhyverun_opt="${bhyverun_opt} -G ${OPTARG}"
+ ;;
+ H)
+ host_base=`realpath ${OPTARG}`
+ ;;
+ i)
+ force_install=1
+ ;;
+ I)
+ isofile=${OPTARG}
+ ;;
+ l)
+ loader_opt="${loader_opt} -l ${OPTARG}"
+ ;;
+ L)
+ vnchost="${OPTARG}"
+ ;;
+ m)
+ memsize=${OPTARG}
+ ;;
+ n)
+ nic=${OPTARG}
+ ;;
+ p)
+ eval "pass_dev${pass_total}=\"${OPTARG}\""
+ pass_total=$(($pass_total + 1))
+ ;;
+ P)
+ vncport="${OPTARG}"
+ ;;
+ t)
+ eval "tap_dev${tap_total}=\"${OPTARG}\""
+ tap_total=$(($tap_total + 1))
+ ;;
+ T)
+ tablet="-s 30,xhci,tablet"
+ ;;
+ u)
+ bhyverun_opt="${bhyverun_opt} -u"
+ ;;
+ v)
+ vncwait=",wait"
+ ;;
+ w)
+ bhyverun_opt="${bhyverun_opt} -w"
+ ;;
+ *)
+ usage
+ ;;
+ esac
+done
+
+if [ $tap_total -eq 0 ] ; then
+ tap_total=1
+ tap_dev0="${DEFAULT_TAPDEV}"
+fi
+if [ $disk_total -eq 0 ] ; then
+ disk_total=1
+ disk_dev0="${DEFAULT_VIRTIO_DISK}"
+
+fi
+
+shift $((${OPTIND} - 1))
+
+if [ $# -ne 1 ]; then
+ usage "virtual machine name not specified"
+fi
+
+vmname="$1"
+if [ -n "${host_base}" ]; then
+ loader_opt="${loader_opt} -h ${host_base}"
+fi
+
+# If PCI passthru devices are configured then guest memory must be wired
+if [ ${pass_total} -gt 0 ]; then
+ loader_opt="${loader_opt} -S"
+ bhyverun_opt="${bhyverun_opt} -S"
+fi
+
+if [ ${efi_mode} -gt 0 ]; then
+ if [ ! -f ${efi_firmware} ]; then
+ echo "Error: EFI Firmware ${efi_firmware} doesn't exist." \
+ "Try: pkg install edk2-bhyve"
+ exit 1
+ fi
+fi
+
+make_and_check_diskdev()
+{
+ local virtio_diskdev="$1"
+ # Create the virtio diskdev file if needed
+ if [ ! -e ${virtio_diskdev} ]; then
+ echo "virtio disk device file \"${virtio_diskdev}\" does not exist."
+ echo "Creating it ..."
+ truncate -s 8G ${virtio_diskdev} > /dev/null
+ fi
+
+ if [ ! -r ${virtio_diskdev} ]; then
+ echo "virtio disk device file \"${virtio_diskdev}\" is not readable"
+ exit 1
+ fi
+
+ if [ ! -w ${virtio_diskdev} ]; then
+ echo "virtio disk device file \"${virtio_diskdev}\" is not writable"
+ exit 1
+ fi
+}
+
+echo "Launching virtual machine \"$vmname\" ..."
+
+first_diskdev="$disk_dev0"
+
+${BHYVECTL} --vm=${vmname} --destroy > /dev/null 2>&1
+
+while [ 1 ]; do
+
+ file -s ${first_diskdev} | grep "boot sector" > /dev/null
+ rc=$?
+ if [ $rc -ne 0 ]; then
+ file -s ${first_diskdev} | \
+ grep ": Unix Fast File sys" > /dev/null
+ rc=$?
+ fi
+ if [ $rc -ne 0 ]; then
+ need_install=1
+ else
+ need_install=0
+ fi
+
+ if [ $force_install -eq 1 -o $need_install -eq 1 ]; then
+ if [ ! -r ${isofile} ]; then
+ echo -n "Installation CDROM image \"${isofile}\" "
+ echo "is not readable"
+ exit 1
+ fi
+ BOOTDISKS="-d ${isofile}"
+ installer_opt="-s 31:0,ahci-cd,${isofile}"
+ else
+ BOOTDISKS=""
+ i=0
+ while [ $i -lt $disk_total ] ; do
+ eval "disk=\$disk_dev${i}"
+ if [ -r ${disk} ] ; then
+ BOOTDISKS="$BOOTDISKS -d ${disk} "
+ fi
+ i=$(($i + 1))
+ done
+ installer_opt=""
+ fi
+
+ if [ ${efi_mode} -eq 0 ]; then
+ ${LOADER} -c ${console} -m ${memsize} ${BOOTDISKS} \
+ ${loader_opt} ${vmname}
+ bhyve_exit=$?
+ if [ $bhyve_exit -ne 0 ]; then
+ break
+ fi
+ fi
+
+ #
+ # Build up args for additional tap and disk devices now.
+ #
+ nextslot=2 # slot 0 is hostbridge, slot 1 is lpc
+ devargs="" # accumulate disk/tap args here
+ i=0
+ while [ $i -lt $tap_total ] ; do
+ eval "tapname=\$tap_dev${i}"
+ devargs="$devargs -s $nextslot:0,${nic},${tapname} "
+ nextslot=$(($nextslot + 1))
+ i=$(($i + 1))
+ done
+
+ i=0
+ while [ $i -lt $disk_total ] ; do
+ eval "disk=\$disk_dev${i}"
+ eval "opts=\$disk_opts${i}"
+ make_and_check_diskdev "${disk}"
+ devargs="$devargs -s $nextslot:0,$disk_emulation,${disk}${opts} "
+ nextslot=$(($nextslot + 1))
+ i=$(($i + 1))
+ done
+
+ i=0
+ while [ $i -lt $pass_total ] ; do
+ eval "pass=\$pass_dev${i}"
+ bsfform="$(echo "${pass}" | grep "^[0-9]\+/[0-9]\+/[0-9]\+$")"
+ if [ -z "${bsfform}" ]; then
+ bsf="$(pciconf -l "${pass}" 2>/dev/null)"
+ if [ $? -ne 0 ]; then
+ errmsg "${pass} is not a host PCI device"
+ exit 1
+ fi
+ bsf="$(echo "${bsf}" | awk -F: '{print $2"/"$3"/"$4}')"
+ else
+ bsf="${pass}"
+ fi
+ devargs="$devargs -s $nextslot:0,passthru,${bsf} "
+ nextslot=$(($nextslot + 1))
+ i=$(($i + 1))
+ done
+
+ efiargs=""
+ if [ ${efi_mode} -gt 0 ]; then
+ efiargs="-s 29,fbuf,tcp=${vnchost}:${vncport},"
+ efiargs="${efiargs}${vncsize}${vncwait}"
+ efiargs="${efiargs} -l bootrom,${efi_firmware}"
+ efiargs="${efiargs} ${tablet}"
+ fi
+
+ ${FBSDRUN} -c ${cpus} -m ${memsize} ${bhyverun_opt} \
+ -s 0:0,hostbridge \
+ -s 1:0,lpc \
+ ${efiargs} \
+ ${devargs} \
+ -l com1,${console} \
+ ${installer_opt} \
+ ${vmname}
+
+ bhyve_exit=$?
+ # bhyve returns the following status codes:
+ # 0 - VM has been reset
+ # 1 - VM has been powered off
+ # 2 - VM has been halted
+ # 3 - VM generated a triple fault
+ # all other non-zero status codes are errors
+ #
+ if [ $bhyve_exit -ne 0 ]; then
+ break
+ fi
+done
+
+
+case $bhyve_exit in
+ 0|1|2)
+ # Cleanup /dev/vmm entry when bhyve did not exit
+ # due to an error.
+ ${BHYVECTL} --vm=${vmname} --destroy > /dev/null 2>&1
+ ;;
+esac
+
+exit $bhyve_exit
diff --git a/share/examples/bootforth/README b/share/examples/bootforth/README
new file mode 100644
index 000000000000..69db86ee8806
--- /dev/null
+++ b/share/examples/bootforth/README
@@ -0,0 +1,33 @@
+Here you can find some simple examples how to use BootFORTH (part of the
+new bootloader) together with terminal emulation code (available when
+compiling /stand/i386/libi386 with -DTERM_EMU).
+
+Normally, you can place the files in /boot as they are here, and they will be
+automatically loaded by /boot/loader. You must choose between boot.4th or
+loader.rc, though. Copy one or the other, but not both. Also, menu.4th is
+only used by boot.4th, and menuconf.4th is only used by loader.rc, so you
+don't need to copy both files.
+
+The files are:
+
+boot.4th example of file which is always loaded by /boot/loader, if
+ present in /boot/
+loader.rc example of file which is always loader by /boot/loader, if
+ present in /boot/
+screen.4th helpful words for screen manipulation.
+frames.4th basic frame drawing primitives. Requires screen.4th.
+menu.4th example of simple startup menu.
+menuconf.4th another example of simples startup menu.
+
+You're encouraged to add more features to these files - I'm not a Forth
+hacker, unfortunately...
+
+Andrzej Bialecki
+<abial@freebsd.org>
+
+If you use loader.rc/menuconf.4th, be sure to create /boot/stable.conf and
+/boot/current.conf, like described in loader.conf(5), with appropriate
+configuration to distinguish one from the other.
+
+Daniel C. Sobral
+<dcs@freebsd.org>
diff --git a/share/examples/bootforth/boot.4th b/share/examples/bootforth/boot.4th
new file mode 100644
index 000000000000..3f75424e46c5
--- /dev/null
+++ b/share/examples/bootforth/boot.4th
@@ -0,0 +1,21 @@
+\ Example of the file which is automatically loaded by /boot/loader
+\ on startup.
+
+\ Load the screen manipulation words
+
+cr .( Loading Forth extensions:)
+
+cr .( - screen.4th...)
+s" /boot/screen.4th" O_RDONLY fopen dup fload fclose
+
+\ Load frame support
+cr .( - frames.4th...)
+s" /boot/frames.4th" O_RDONLY fopen dup fload fclose
+
+\ Load our little menu
+cr .( - menu.4th...)
+s" /boot/menu.4th" O_RDONLY fopen dup fload fclose
+
+\ Show it
+cr
+main_menu
diff --git a/share/examples/bootforth/frames.4th b/share/examples/bootforth/frames.4th
new file mode 100644
index 000000000000..0adcf9ef648b
--- /dev/null
+++ b/share/examples/bootforth/frames.4th
@@ -0,0 +1,88 @@
+\ Words implementing frame drawing
+\ XXX Filled boxes are left as an exercise for the reader... ;-/
+
+marker task-frames.4th
+
+variable h_el
+variable v_el
+variable lt_el
+variable lb_el
+variable rt_el
+variable rb_el
+variable fill
+
+\ Single frames
+196 constant sh_el
+179 constant sv_el
+218 constant slt_el
+192 constant slb_el
+191 constant srt_el
+217 constant srb_el
+\ Double frames
+205 constant dh_el
+186 constant dv_el
+201 constant dlt_el
+200 constant dlb_el
+187 constant drt_el
+188 constant drb_el
+\ Fillings
+0 constant fill_none
+32 constant fill_blank
+176 constant fill_dark
+177 constant fill_med
+178 constant fill_bright
+
+: hline ( len x y -- ) \ Draw horizontal single line
+ at-xy \ move cursor
+ 0 do
+ h_el @ emit
+ loop
+;
+
+: f_single ( -- ) \ set frames to single
+ sh_el h_el !
+ sv_el v_el !
+ slt_el lt_el !
+ slb_el lb_el !
+ srt_el rt_el !
+ srb_el rb_el !
+;
+
+: f_double ( -- ) \ set frames to double
+ dh_el h_el !
+ dv_el v_el !
+ dlt_el lt_el !
+ dlb_el lb_el !
+ drt_el rt_el !
+ drb_el rb_el !
+;
+
+: vline ( len x y -- ) \ Draw vertical single line
+ 2dup 4 pick
+ 0 do
+ at-xy
+ v_el @ emit
+ 1+
+ 2dup
+ loop
+ 2drop 2drop drop
+;
+
+: box ( w h x y -- ) \ Draw a box
+ 2dup 1+ 4 pick 1- -rot
+ vline \ Draw left vert line
+ 2dup 1+ swap 5 pick + swap 4 pick 1- -rot
+ vline \ Draw right vert line
+ 2dup swap 1+ swap 5 pick 1- -rot
+ hline \ Draw top horiz line
+ 2dup swap 1+ swap 4 pick + 5 pick 1- -rot
+ hline \ Draw bottom horiz line
+ 2dup at-xy lt_el @ emit \ Draw left-top corner
+ 2dup 4 pick + at-xy lb_el @ emit \ Draw left bottom corner
+ 2dup swap 5 pick + swap at-xy rt_el @ emit \ Draw right top corner
+ 2 pick + swap 3 pick + swap at-xy rb_el @ emit
+ 2drop
+;
+
+f_single
+fill_none fill !
diff --git a/share/examples/bootforth/loader.rc b/share/examples/bootforth/loader.rc
new file mode 100644
index 000000000000..e8aa549f5905
--- /dev/null
+++ b/share/examples/bootforth/loader.rc
@@ -0,0 +1,33 @@
+\ Example of the file which is automatically loaded by /boot/loader
+\ on startup.
+
+cr .( Loading Forth extensions:)
+
+\ Load configuration file words
+
+cr .( - loader.4th...)
+
+include /boot/loader.4th
+
+\ Load the screen manipulation words
+
+cr .( - screen.4th...)
+s" /boot/screen.4th" O_RDONLY fopen dup fload fclose
+
+\ Load frame support
+cr .( - frames.4th...)
+s" /boot/frames.4th" O_RDONLY fopen dup fload fclose
+
+\ Load our little menu
+cr .( - menuconf.4th...)
+s" /boot/menuconf.4th" O_RDONLY fopen dup fload fclose
+
+\ Initialize loader.4th stuff
+
+cr cr .( Initializing loader.4th...)
+initialize drop
+
+\ Show the menu
+cr
+main_menu
+
diff --git a/share/examples/bootforth/menu.4th b/share/examples/bootforth/menu.4th
new file mode 100644
index 000000000000..3462ea9fc5a9
--- /dev/null
+++ b/share/examples/bootforth/menu.4th
@@ -0,0 +1,98 @@
+\ Simple greeting screen, presenting basic options.
+\ XXX This is far too trivial - I don't have time now to think
+\ XXX about something more fancy... :-/
+
+: title
+ f_single
+ 60 11 10 4 box
+ 29 4 at-xy 15 fg 7 bg
+ ." Welcome to BootFORTH!"
+ me
+;
+
+: menu
+ 2 fg
+ 20 7 at-xy
+ ." 1. Start FreeBSD /kernel."
+ 20 8 at-xy
+ ." 2. Interact with BootFORTH."
+ 20 9 at-xy
+ ." 3. Reboot."
+ me
+;
+
+: tkey ( d -- flag | char )
+ seconds +
+ begin 1 while
+ dup seconds u< if
+ drop
+ -1
+ exit
+ then
+ key? if
+ drop
+ key
+ exit
+ then
+ repeat
+;
+
+: prompt
+ 14 fg
+ 20 11 at-xy
+ ." Enter your option (1,2,3): "
+ 10 tkey
+ dup 32 = if
+ drop key
+ then
+ dup 0< if
+ drop 49
+ then
+ dup emit
+ me
+;
+
+: help_text
+ 10 18 at-xy ." * Choose 1 if you just want to run FreeBSD."
+ 10 19 at-xy ." * Choose 2 if you want to use bootloader facilities."
+ 12 20 at-xy ." See '?' for available commands, and 'words' for"
+ 12 21 at-xy ." complete list of Forth words."
+ 10 22 at-xy ." * Choose 3 in order to warm boot your machine."
+;
+
+: (boot) 0 boot ;
+: (reboot) 0 reboot ;
+
+: main_menu
+ begin 1 while
+ clear
+ f_double
+ 79 23 1 1 box
+ title
+ menu
+ help_text
+ prompt
+ cr cr cr
+ dup 49 = if
+ drop
+ 1 25 at-xy cr
+ ." Loading kernel. Please wait..." cr
+ ['] (boot) catch abort" Error booting"
+ then
+ dup 50 = if
+ drop
+ 1 25 at-xy cr
+ exit
+ then
+ dup 51 = if
+ drop
+ 1 25 at-xy cr
+ ['] (reboot) catch abort" Error rebooting"
+ then
+ 20 12 at-xy
+ ." Key " emit ." is not a valid option!"
+ 20 13 at-xy
+ ." Press any key to continue..."
+ key drop
+ repeat
+;
diff --git a/share/examples/bootforth/menuconf.4th b/share/examples/bootforth/menuconf.4th
new file mode 100644
index 000000000000..df53e812aabc
--- /dev/null
+++ b/share/examples/bootforth/menuconf.4th
@@ -0,0 +1,109 @@
+\ Simple greeting screen, presenting basic options.
+\ XXX This is far too trivial - I don't have time now to think
+\ XXX about something more fancy... :-/
+
+: title
+ f_single
+ 60 11 10 4 box
+ 29 4 at-xy 15 fg 7 bg
+ ." Welcome to BootFORTH!"
+ me
+;
+
+: menu
+ 2 fg
+ 20 7 at-xy
+ ." 1. Start FreeBSD with /boot/stable.conf."
+ 20 8 at-xy
+ ." 2. Start FreeBSD with /boot/current.conf."
+ 20 9 at-xy
+ ." 3. Start FreeBSD with standard configuration. "
+ 20 10 at-xy
+ ." 4. Reboot."
+ me
+;
+
+: tkey ( d -- flag | char )
+ seconds +
+ begin 1 while
+ dup seconds u< if
+ drop
+ -1
+ exit
+ then
+ key? if
+ drop
+ key
+ exit
+ then
+ repeat
+;
+
+: prompt
+ 14 fg
+ 20 12 at-xy
+ ." Enter your option (1,2,3,4): "
+ 10 tkey
+ dup 32 = if
+ drop key
+ then
+ dup 0< if
+ drop 51
+ then
+ dup emit
+ me
+;
+
+: help_text
+ 10 18 at-xy ." * Choose 1 or 2 to run special configuration file."
+ 10 19 at-xy ." * Choose 3 to proceed with standard bootstrapping."
+ 12 20 at-xy ." See '?' for available commands, and 'words' for"
+ 12 21 at-xy ." complete list of Forth words."
+ 10 22 at-xy ." * Choose 4 in order to warm boot your machine."
+;
+
+: (reboot) 0 reboot ;
+
+: main_menu
+ begin 1 while
+ clear
+ f_double
+ 79 23 1 1 box
+ title
+ menu
+ help_text
+ prompt
+ cr cr cr
+ dup 49 = if
+ drop
+ 1 25 at-xy cr
+ ." Loading /boot/stable.conf. Please wait..." cr
+ s" /boot/stable.conf" read-conf
+ 0 boot-conf exit
+ then
+ dup 50 = if
+ drop
+ 1 25 at-xy cr
+ ." Loading /boot/current.conf. Please wait..." cr
+ s" /boot/current.conf" read-conf
+ 0 boot-conf exit
+ then
+ dup 51 = if
+ drop
+ 1 25 at-xy cr
+ ." Proceeding with standard boot. Please wait..." cr
+ 0 boot-conf exit
+ then
+ dup 52 = if
+ drop
+ 1 25 at-xy cr
+ ['] (reboot) catch abort" Error rebooting"
+ then
+ 20 12 at-xy
+ ." Key " emit ." is not a valid option!"
+ 20 13 at-xy
+ ." Press any key to continue..."
+ key drop
+ repeat
+;
+
diff --git a/share/examples/bootforth/screen.4th b/share/examples/bootforth/screen.4th
new file mode 100644
index 000000000000..8bd873f48884
--- /dev/null
+++ b/share/examples/bootforth/screen.4th
@@ -0,0 +1,35 @@
+\ Screen manipulation related words.
+
+marker task-screen.4th
+
+: escc ( -- ) \ emit Esc-[
+ 91 27 emit emit
+;
+
+: ho ( -- ) \ Home cursor
+ escc 72 emit \ Esc-[H
+;
+
+: cld ( -- ) \ Clear from current position to end of display
+ escc 74 emit \ Esc-[J
+;
+
+: clear ( -- ) \ clear screen
+ ho cld
+;
+
+: at-xy ( x y -- ) \ move cursor to x rows, y cols (1-based coords)
+ escc .# 59 emit .# 72 emit \ Esc-[%d;%dH
+;
+
+: fg ( x -- ) \ Set foreground color
+ escc 3 .# .# 109 emit \ Esc-[3%dm
+;
+
+: bg ( x -- ) \ Set background color
+ escc 4 .# .# 109 emit \ Esc-[4%dm
+;
+
+: me ( -- ) \ Mode end (clear attributes)
+ escc 109 emit
+;
diff --git a/share/examples/csh/dot.cshrc b/share/examples/csh/dot.cshrc
new file mode 100644
index 000000000000..5cda009dbd96
--- /dev/null
+++ b/share/examples/csh/dot.cshrc
@@ -0,0 +1,139 @@
+# Here are some example (t)csh options and configurations that you may find interesting
+#
+#
+
+# Sets SSH_AUTH_SOCK to the user's ssh-agent socket path if running
+#
+# This has a couple caveats, the most notable being that if a user
+# has multiple ssh-agent(1) processes running, this will very likely
+# set SSH_AUTH_SOCK to point to the wrong file/domain socket.
+if (${?SSH_AUTH_SOCK} != "1") then
+ setenv SSH_AUTH_SOCK `sockstat -u | awk '/^${USER}.+ ssh-agent/ { print $6 }'`
+endif
+
+# Change only root's prompt
+if (`id -g` == 0) then
+ set prompt="root@%m# "
+endif
+
+# This maps the "Delete" key to do the right thing
+# Pressing CTRL-v followed by the key of interest will print the shell's
+# mapping for the key
+bindkey "^[[3~" delete-char-or-list-or-eof
+
+# Make the Ins key work
+bindkey "\e[2~" overwrite-mode
+
+# Some common completions
+complete cd 'p/1/d/'
+complete chown 'p/1/u/'
+complete dd 'c/[io]f=/f/ n/*/"(if of ibs obs bs skip seek count)"/='
+complete find 'n/-fstype/"(nfs 4.2)"/' 'n/-name/f/' \
+ 'n/-type/(c b d f p l s)/' \
+ 'n/-user/u/ n/-group/g/' \
+ 'n/-exec/c/' 'n/-ok/c/' \
+ 'n/-cpio/f/' \
+ 'n/-ncpio/f/' \
+ 'n/-newer/f/' \
+ 'c/-/(fstype name perm prune type user nouser group nogroup size inum atime mtime ctime exec \
+ ok print ls cpio ncpio newer xdev depth daystart follow maxdepth mindepth noleaf version \
+ anewer cnewer amin cmin mmin true false uid gid ilname iname ipath iregex links lname empty path \
+ regex used xtype fprint fprint0 fprintf print0 printf not a and o or)/' \
+ 'n/*/d/'
+complete fg 'c/%/j/'
+complete gpart 'p/1/(add backup bootcode commit create delete destroy modify recover resize restore set show undo unset)/' \
+ 'n/add/x:-t type [-a alignment] [-b start] [-s size] [-i index] [-l label] -f flags geom/' \
+ 'n/backup/x:geom/' \
+ 'n/bootcode/x:[-b bootcode] [-p partcode -i index] [-f flags] geom/' \
+ 'n/commit/x:geom/' \
+ 'n/create/x:-s scheme [-n entries] [-f flags] provider/' \
+ 'n/delete/x:-i index [-f flags] geom/' \
+ 'n/destroy/x:[-F] [-f flags] geom/' \
+ 'n/modify/x:-i index [-l label] [-t type] [-f flags] geom/' \
+ 'n/recover/x:[-f flags] geom/' \
+ 'n/resize/x:-i index [-a alignment] [-s size] [-f flags] geom/' \
+ 'n/restore/x:[-lF] [-f flags] provider [...]/' \
+ 'n/set/x:-a attrib -i index [-f flags] geom/' \
+ 'n/show/x:[-l | -r] [-p] [geom ...]/' \
+ 'n/undo/x:geom/' \
+ 'n/unset/x:-a attrib -i index [-f flags] geom/'
+complete grep 'c/-*A/x:<#_lines_after>/' \
+ 'c/-*B/x:<#_lines_before>/' \
+ 'c/--/(extended-regexp fixed-regexp basic-regexp regexp file ignore-case word-regexp line-regexp \
+ no-messages revert-match version help byte-offset line-number with-filename no-filename quiet silent \
+ text directories recursive files-without-match files-with-matches count before-context after-context \
+ context binary unix-byte-offsets)/' \
+ 'c/-/(A a B b C c d E e F f G H h i L l n q r s U u V v w x)/' \
+ 'p/1/x:<limited_regular_expression>/ N/-*e/f/' \
+ 'n/-*e/x:<limited_regular_expression>/' \
+ 'n/-*f/f/' \
+ 'n/*/f/'
+complete ifconfig 'p@1@`ifconfig -l`@' \
+ 'n/*/(range phase link netmask mtu vlandev vlan metric mediaopt down delete broadcast arp debug)/' \
+ 'c/%/j/' \
+ 'n/*/`ps -ax | awk '"'"'{print $1}'"'"'`/'
+complete kill 'c/-/S/' 'c/%/j/' 'n/*/`ps -ax | awk '"'"'{print $1}'"'"'`/'
+complete killall 'c/-/S/' 'c/%/j/' 'n/*/`ps -ax | awk '"'"'{print $5}'"'"'`/'
+complete kldload 'n@*@`ls -1 /boot/modules/ /boot/kernel/ | awk -F/ \$NF\ \~\ \".ko\"\ \{sub\(\/\.ko\/,\"\",\$NF\)\;print\ \$NF\}`@'
+complete kldunload 'n@*@`kldstat | awk \{sub\(\/\.ko\/,\"\",\$NF\)\;print\ \$NF\} | grep -v Name`@'
+complete make 'p@1@`make -pn | sed -n -E "/^[#_.\/[:blank:]]+/d; /=/d; s/[[:blank:]]*:.*//gp;"`@' \
+ 'n@-V@`make -ndv | & grep Global: | sed -E -e "s/^Global://" -e "s/ .*//" -e "/^[[:lower:]]/d" | sort | uniq`@'
+complete man 'C/*/c/'
+complete netstat 'n@-I@`ifconfig -l`@'
+complete pkg_delete 'c/-/(i v D n p d f G x X r)/' 'n@*@`ls /var/db/pkg`@'
+complete pkg_info 'c/-/(a b v p q Q c d D f g i I j k K r R m L s o G O x X e E l t V P)/' 'n@*@`\ls -1 /var/db/pkg | sed s%/var/db/pkg/%%`@'
+complete ping 'p/1/$hosts/'
+complete pkill 'c/-/S/' \
+ 'n@*@`ps -axc -o command="" | sort | uniq`@'
+complete portmaster 'c/--/(always-fetch check-depends check-port-dbdir clean-distfiles clean-packages delete-build-only \
+ delete-packages force-config help index index-first index-only list-origins local-packagedir \
+ no-confirm no-index-fetch no-term-title packages packages-build packages-if-newer packages-local \
+ packages-only show-work update-if-newer version)/' \
+ 'c/-/(a b B C d D e f F g G h H i l L m n o p r R s t u v w x)/' \
+ 'n@*@`pkg_info -E \*`@'
+complete rsync "c,*:/,F:/," \
+ "c,*:,F:$HOME," \
+ 'c/*@/$hosts/:/'
+complete scp "c,*:/,F:/," \
+ "c,*:,F:$HOME," \
+ 'c/*@/$hosts/:/'
+complete service 'c/-/(e l r v)/' 'p/1/`service -l`/' 'n/*/(start stop reload restart status rcvar describe extracommands onestart onestop oneextracommands)/'
+complete svn 'C@file:///@`'"${HOME}/etc/tcsh/complete.d/svn"'`@@' \
+ 'n@ls@(file:/// svn+ssh:// svn://)@@' \
+ 'n@help@(add blame cat checkout cleanup commit copy delete export help import info list ls lock log merge mkdir move propdel \
+ propedit propget proplist propset resolved revert status switch unlock update)@' 'p@1@(add blame cat checkout cleanup commit \
+ copy delete export help import info list ls lock log merge mkdir move propdel propedit propget proplist propset resolved \
+ revert status switch unlock update)@'
+complete ssh 'p/1/$hosts/' \
+ 'c/-/(l n)/' \
+ 'n/-l/u/ N/-l/c/ n/-/c/ p/2/c/ p/*/f/'
+complete sysctl 'n/*/`sysctl -Na`/'
+complete tmux 'n/*/(attach detach has kill-server kill-session lsc lscm ls lockc locks new refresh rename showmsgs source start suspendc switchc)/'
+complete which 'C/*/c/'
+
+if ( -f /etc/printcap ) then
+ set printers=(`sed -n -e "/^[^ #].*:/s/:.*//p" /etc/printcap`)
+ complete lpr 'c/-P/$printers/'
+ complete lpq 'c/-P/$printers/'
+ complete lprm 'c/-P/$printers/'
+endif
+
+# Alternate prompts
+set prompt = '#'
+set prompt = '%B%m%b%# '
+set prompt = '%B%m%b:%c03:%# '
+set prompt = '%{\033]0;%n@%m:%/\007%}%B%m%b:%c03:%# '
+set prompt = "%n@%m %c04%m%# "
+set prompt = "%n@%m:%c04 %# "
+set prompt = "[%n@%m]%c04%# "
+set ellipsis
+
+# Color ls
+alias ll ls -lAhG
+alias ls ls -G
+
+# Color on many system utilities
+setenv CLICOLOR 1
+
+# other autolist options
+set autolist = TAB
diff --git a/share/examples/drivers/README b/share/examples/drivers/README
new file mode 100644
index 000000000000..8628029a62f8
--- /dev/null
+++ b/share/examples/drivers/README
@@ -0,0 +1,42 @@
+
+Author: Julian Elischer
+
+The files in this directory are shell scripts.
+
+They will, when run, create an example skeleton driver
+for you. You can use this driver as a starting point for
+writing drivers for your own devices. They have all the hooks needed
+for initialization, probing, attaching, as well as DEVFS
+node creation. They also create sample ioctl commands and a sample
+ioctl definition .h file in /sys/sys. In other words they are fully
+functional in a 'skeleton' sort of a way. They support multiple devices
+so that you may have several of your 'foobar' devices probed and attached
+at once.
+
+I expect that these scripts will improve with time.
+
+At present these scripts also link the newly created driver into
+the kernel sources in /sys. Possibly a better way would be
+to make them interactive. (and ask what kernel tree to use as well as
+a name for the driver.).
+
+There are presently two scripts.
+One for making a real device driver for ISA devices, and
+one for making a device driver for pseudo devices (e.g. /dev/null).
+Hopefully they will be joined by similar scripts for creating
+skeletons for PCI devices as well.
+
+Give them a single argument: the name of the driver.
+They will use this given name in many places within the driver,
+both in lower and upper case form. (conforming to normal usage).
+
+The skeleton driver should already link with the kernel
+and in fact the shell script will compile a kernel with the new
+drive linked in.. The new kernel should still be
+runnable and the new driver should be
+fully callable (once you get your device to probe).
+You should simply edit the driver and continue to use
+'make' (as done in the script) until your driver does what you want.
+
+The driver will end up in /sys/i386/isa for the device driver script,
+and in /sys/dev for the pseudo driver script.
diff --git a/share/examples/drivers/make_device_driver.sh b/share/examples/drivers/make_device_driver.sh
new file mode 100755
index 000000000000..5b8f8efa6469
--- /dev/null
+++ b/share/examples/drivers/make_device_driver.sh
@@ -0,0 +1,1005 @@
+#!/bin/sh
+# This writes a skeleton driver and puts it into the kernel tree for you.
+# It also adds FOO and files.FOO configuration files so you can compile
+# a kernel with your FOO driver linked in.
+# To do so:
+# cd /usr/src; make buildkernel KERNCONF=FOO
+#
+# More interestingly, it creates a modules/foo directory
+# which it populates, to allow you to compile a FOO module
+# which can be linked with your presently running kernel (if you feel brave).
+# To do so:
+# cd /sys/modules/foo; make depend; make; make install; kldload foo
+#
+# arg1 to this script is expected to be lowercase "foo"
+# arg2 path to the kernel sources, "/sys" if omitted
+#
+# Trust me, RUN THIS SCRIPT :)
+#
+# TODO:
+# o generate foo_isa.c, foo_pci.c, foo_pccard.c, foo_cardbus.c, and foovar.h
+# o Put pccard stuff in here.
+#
+#
+#
+if [ "X${1}" = "X" ]; then
+ echo "Hey, how about some help here... give me a device name!"
+ exit 1
+fi
+if [ "X${2}" = "X" ]; then
+ TOP=`cd /sys; pwd -P`
+ echo "Using ${TOP} as the path to the kernel sources!"
+else
+ TOP=${2}
+fi
+UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"`
+
+if [ -d ${TOP}/modules/${1} ]; then
+ echo "There appears to already be a module called ${1}"
+ echo -n "Should it be overwritten? [Y]"
+ read VAL
+ if [ "-z" "$VAL" ]; then
+ VAL=YES
+ fi
+ case ${VAL} in
+ [yY]*)
+ echo "Cleaning up from prior runs"
+ rm -rf ${TOP}/dev/${1}
+ rm -rf ${TOP}/modules/${1}
+ rm ${TOP}/conf/files.${UPPER}
+ rm ${TOP}/i386/conf/${UPPER}
+ rm ${TOP}/sys/${1}io.h
+ ;;
+ *)
+ exit 1
+ ;;
+ esac
+fi
+
+echo "The following files will be created:"
+echo ${TOP}/modules/${1}
+echo ${TOP}/conf/files.${UPPER}
+echo ${TOP}/i386/conf/${UPPER}
+echo ${TOP}/dev/${1}
+echo ${TOP}/dev/${1}/${1}.c
+echo ${TOP}/sys/${1}io.h
+echo ${TOP}/modules/${1}
+echo ${TOP}/modules/${1}/Makefile
+
+ mkdir ${TOP}/modules/${1}
+
+#######################################################################
+#######################################################################
+#
+# Create configuration information needed to create a kernel
+# containing this driver.
+#
+# Not really needed if we are going to do this as a module.
+#######################################################################
+# First add the file to a local file list.
+#######################################################################
+
+cat >${TOP}/conf/files.${UPPER} <<DONE
+dev/${1}/${1}.c optional ${1}
+DONE
+
+#######################################################################
+# Then create a configuration file for a kernel that contains this driver.
+#######################################################################
+cat >${TOP}/i386/conf/${UPPER} <<DONE
+# Configuration file for kernel type: ${UPPER}
+
+files "${TOP}/conf/files.${UPPER}"
+
+include GENERIC
+
+ident ${UPPER}
+
+DONE
+
+cat >>${TOP}/i386/conf/${UPPER} <<DONE
+# trust me, you'll need this
+options KDB
+options DDB
+device ${1}
+DONE
+
+if [ ! -d ${TOP}/dev/${1} ]; then
+ mkdir -p ${TOP}/dev/${1}
+fi
+
+cat >${TOP}/dev/${1}/${1}.c <<DONE
+/*
+ * Copyright (c) [year] [your name]
+ *
+ * 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.
+ */
+
+/*
+ * http://www.daemonnews.org/200008/isa.html is required reading.
+ * hopefully it will make it's way into the handbook.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h> /* cdevsw stuff */
+#include <sys/kernel.h> /* SYSINIT stuff */
+#include <sys/uio.h> /* SYSINIT stuff */
+#include <sys/malloc.h> /* malloc region definitions */
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/${1}io.h> /* ${1} IOCTL definitions */
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/rman.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include <isa/isavar.h>
+
+#include "isa_if.h"
+
+/* XXX These should be defined in terms of bus-space ops. */
+#define ${UPPER}_INB(port) inb(port_start)
+#define ${UPPER}_OUTB(port, val) ( port_start, (val))
+#define SOME_PORT 123
+#define EXPECTED_VALUE 0x42
+
+/*
+ * The softc is automatically allocated by the parent bus using the
+ * size specified in the driver_t declaration below.
+ */
+#define DEV2SOFTC(dev) ((struct ${1}_softc *) (dev)->si_drv1)
+#define DEVICE2SOFTC(dev) ((struct ${1}_softc *) device_get_softc(dev))
+
+/*
+ * Device specific misc defines.
+ */
+#define BUFFERSIZE 1024
+#define NUMPORTS 4
+#define MEMSIZE (4 * 1024) /* Imaginable h/w buffer size. */
+
+/*
+ * One of these per allocated device.
+ */
+struct ${1}_softc {
+ bus_space_tag_t bt;
+ bus_space_handle_t bh;
+ int rid_ioport;
+ int rid_memory;
+ int rid_irq;
+ int rid_drq;
+ struct resource* res_ioport; /* Resource for port range. */
+ struct resource* res_memory; /* Resource for mem range. */
+ struct resource* res_irq; /* Resource for irq range. */
+ struct resource* res_drq; /* Resource for dma channel. */
+ device_t device;
+ struct cdev *dev;
+ void *intr_cookie;
+ void *vaddr; /* Virtual address of mem resource. */
+ char buffer[BUFFERSIZE]; /* If we need to buffer something. */
+};
+
+/* Function prototypes (these should all be static). */
+static int ${1}_deallocate_resources(device_t device);
+static int ${1}_allocate_resources(device_t device);
+static int ${1}_attach(device_t device, struct ${1}_softc *scp);
+static int ${1}_detach(device_t device, struct ${1}_softc *scp);
+
+static d_open_t ${1}open;
+static d_close_t ${1}close;
+static d_read_t ${1}read;
+static d_write_t ${1}write;
+static d_ioctl_t ${1}ioctl;
+static d_mmap_t ${1}mmap;
+static d_poll_t ${1}poll;
+static void ${1}intr(void *arg);
+
+static struct cdevsw ${1}_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = ${1}open,
+ .d_close = ${1}close,
+ .d_read = ${1}read,
+ .d_write = ${1}write,
+ .d_ioctl = ${1}ioctl,
+ .d_poll = ${1}poll,
+ .d_mmap = ${1}mmap,
+ .d_name = "${1}",
+};
+
+static devclass_t ${1}_devclass;
+
+/*
+ ******************************************
+ * ISA Attachment structures and functions.
+ ******************************************
+ */
+static void ${1}_isa_identify (driver_t *, device_t);
+static int ${1}_isa_probe (device_t);
+static int ${1}_isa_attach (device_t);
+static int ${1}_isa_detach (device_t);
+
+static struct isa_pnp_id ${1}_ids[] = {
+ {0x12345678, "ABCco Widget"},
+ {0xfedcba98, "shining moon Widget ripoff"},
+ {0, NULL}
+};
+
+static device_method_t ${1}_methods[] = {
+ DEVMETHOD(device_identify, ${1}_isa_identify),
+ DEVMETHOD(device_probe, ${1}_isa_probe),
+ DEVMETHOD(device_attach, ${1}_isa_attach),
+ DEVMETHOD(device_detach, ${1}_isa_detach),
+ DEVMETHOD_END
+};
+
+static driver_t ${1}_isa_driver = {
+ "${1}",
+ ${1}_methods,
+ sizeof (struct ${1}_softc)
+};
+
+DRIVER_MODULE(${1}, isa, ${1}_isa_driver, ${1}_devclass, 0, 0);
+
+/*
+ * Here list some port addresses we might expect our widget to appear at:
+ * This list should only be used for cards that have some non-destructive
+ * (to other cards) way of probing these address. Otherwise the driver
+ * should not go looking for instances of itself, but instead rely on
+ * the hints file. Strange failures for people with other cards might
+ * result.
+ */
+static struct localhints {
+ int ioport;
+ int irq;
+ int drq;
+ int mem;
+} res[] = {
+ { 0x210, 11, 2, 0xcd000},
+ { 0x310, 12, 3, 0xdd000},
+ { 0x320, 9, 6, 0xd4000},
+ {0,0,0,0}
+};
+
+#define MAXHINTS 10 /* Just an arbitrary safety limit. */
+/*
+ * Called once when the driver is somehow connected with the bus,
+ * (Either linked in and the bus is started, or loaded as a module).
+ *
+ * The aim of this routine in an ISA driver is to add child entries to
+ * the parent bus so that it looks as if the devices were detected by
+ * some pnp-like method, or at least mentioned in the hints.
+ *
+ * For NON-PNP "dumb" devices:
+ * Add entries into the bus's list of likely devices, so that
+ * our 'probe routine' will be called for them.
+ * This is similar to what the 'hints' code achieves, except this is
+ * loadable with the driver.
+ * In the 'dumb' case we end up with more children than needed but
+ * some (or all) of them will fail probe() and only waste a little memory.
+ *
+ * For NON-PNP "Smart" devices:
+ * If the device has a NON-PNP way of being detected and setting/sensing
+ * the card, then do that here and add a child for each set of
+ * hardware found.
+ *
+ * For PNP devices:
+ * If the device is always PNP capable then this function can be removed.
+ * The ISA PNP system will have automatically added it to the system and
+ * so your identify routine needn't do anything.
+ *
+ * If the device is mentioned in the 'hints' file then this
+ * function can be removed. All devices mentioned in the hints
+ * file get added as children for probing, whether or not the
+ * driver is linked in. So even as a module it MAY still be there.
+ * See isa/isahint.c for hints being added in.
+ */
+static void
+${1}_isa_identify (driver_t *driver, device_t parent)
+{
+ u_int32_t irq=0;
+ u_int32_t ioport;
+ device_t child;
+ int i;
+
+ /*
+ * If we've already got ${UPPER} attached somehow, don't try again.
+ * Maybe it was in the hints file. or it was loaded before.
+ */
+ if (device_find_child(parent, "${1}", 0)) {
+ printf("${UPPER}: already attached\n");
+ return;
+ }
+/* XXX Look at dev/acpica/acpi_isa.c for use of ISA_ADD_CONFIG() macro. */
+/* XXX What is ISA_SET_CONFIG_CALLBACK(parent, child, pnpbios_set_config, 0)? */
+ for (i = 0; i < MAXHINTS; i++) {
+
+ ioport = res[i].ioport;
+ irq = res[i].irq;
+ if ((ioport == 0) && (irq == 0))
+ return; /* We've added all our local hints. */
+
+ child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "${1}", -1);
+ bus_set_resource(child, SYS_RES_IOPORT, 0, ioport, NUMPORTS);
+ bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
+ bus_set_resource(child, SYS_RES_DRQ, 0, res[i].drq, 1);
+ bus_set_resource(child, SYS_RES_MEMORY, 0, res[i].mem, MEMSIZE);
+
+#if 0
+ /*
+ * If we wanted to pretend PNP found it
+ * we could do this, and put matching entries
+ * in the PNP table, but I think it's probably too hacky.
+ * As you see, some people have done it though.
+ * Basically EISA (remember that?) would do this I think.
+ */
+ isa_set_vendorid(child, PNP_EISAID("ESS1888"));
+ isa_set_logicalid(child, PNP_EISAID("ESS1888"));
+#endif
+ }
+#if 0
+ /*
+ * Do some smart probing (e.g. like the lnc driver)
+ * and add a child for each one found.
+ */
+#endif
+
+ return;
+}
+/*
+ * The ISA code calls this for each device it knows about,
+ * whether via the PNP code or via the hints etc.
+ * If the device nas no PNP capabilities, remove all the
+ * PNP entries, but keep the call to ISA_PNP_PROBE()
+ * As it will guard against accidentally recognising
+ * foreign hardware. This is because we will be called to check against
+ * ALL PNP hardware.
+ */
+static int
+${1}_isa_probe (device_t device)
+{
+ int error;
+ device_t parent = device_get_parent(device);
+ struct ${1}_softc *scp = DEVICE2SOFTC(device);
+ u_long port_start, port_count;
+
+ bzero(scp, sizeof(*scp));
+ scp->device = device;
+
+ /*
+ * Check this device for a PNP match in our table.
+ * There are several possible outcomes.
+ * error == 0 We match a PNP.
+ * error == ENXIO, It is a PNP device but not in our table.
+ * error == ENOENT, It is not a PNP device.. try heuristic probes.
+ * -- logic from if_ed_isa.c, added info from isa/isa_if.m:
+ *
+ * If we had a list of devices that we could handle really well,
+ * and a list which we could handle only basic functions, then
+ * we would call this twice, once for each list,
+ * and return a value of '-2' or something if we could
+ * only handle basic functions. This would allow a specific
+ * Widgetplus driver to make a better offer if it knows how to
+ * do all the extended functions. (See non-pnp part for more info).
+ */
+ error = ISA_PNP_PROBE(parent, device, ${1}_ids);
+ switch (error) {
+ case 0:
+ /*
+ * We found a PNP device.
+ * Do nothing, as it's all done in attach().
+ */
+ break;
+ case ENOENT:
+ /*
+ * Well it didn't show up in the PNP tables
+ * so look directly at known ports (if we have any)
+ * in case we are looking for an old pre-PNP card.
+ *
+ * Hopefully the 'identify' routine will have picked these
+ * up for us first if they use some proprietary detection
+ * method.
+ *
+ * The ports, irqs etc should come from a 'hints' section
+ * which is read in by code in isa/isahint.c
+ * and kern/subr_bus.c to create resource entries,
+ * or have been added by the 'identify routine above.
+ * Note that HINTS based resource requests have NO
+ * SIZE for the memory or ports requests (just a base)
+ * so we may need to 'correct' this before we
+ * do any probing.
+ */
+ /*
+ * Find out the values of any resources we
+ * need for our dumb probe. Also check we have enough ports
+ * in the request. (could be hints based).
+ * Should probably do the same for memory regions too.
+ */
+ error = bus_get_resource(device, SYS_RES_IOPORT, 0,
+ &port_start, &port_count);
+ if (port_count != NUMPORTS) {
+ bus_set_resource(device, SYS_RES_IOPORT, 0,
+ port_start, NUMPORTS);
+ }
+
+ /*
+ * Make a temporary resource reservation.
+ * If we can't get the resources we need then
+ * we need to abort. Possibly this indicates
+ * the resources were used by another device
+ * in which case the probe would have failed anyhow.
+ */
+ if ((error = (${1}_allocate_resources(device)))) {
+ error = ENXIO;
+ goto errexit;
+ }
+
+ /* Dummy heuristic type probe. */
+ if (inb(port_start) != EXPECTED_VALUE) {
+ /*
+ * It isn't what we hoped, so quit looking for it.
+ */
+ error = ENXIO;
+ } else {
+ u_long membase = bus_get_resource_start(device,
+ SYS_RES_MEMORY, 0 /*rid*/);
+ u_long memsize;
+ /*
+ * If we discover in some way that the device has
+ * XXX bytes of memory window, we can override
+ * or set the memory size in the child resource list.
+ */
+ memsize = inb(port_start + 1) * 1024; /* for example */
+ error = bus_set_resource(device, SYS_RES_MEMORY,
+ /*rid*/0, membase, memsize);
+ /*
+ * We found one, return non-positive numbers..
+ * Return -N if we can't handle it, but not well.
+ * Return -2 if we would LIKE the device.
+ * Return -1 if we want it a lot.
+ * Return 0 if we MUST get the device.
+ * This allows drivers to 'bid' for a device.
+ */
+ device_set_desc(device, "ACME Widget model 1234");
+ error = -1; /* We want it but someone else
+ may be even better. */
+ }
+ /*
+ * Unreserve the resources for now because
+ * another driver may bid for device too.
+ * If we lose the bid, but still hold the resources, we will
+ * effectively have disabled the other driver from getting them
+ * which will result in neither driver getting the device.
+ * We will ask for them again in attach if we win.
+ */
+ ${1}_deallocate_resources(device);
+ break;
+ case ENXIO:
+ /* It was PNP but not ours, leave immediately. */
+ default:
+ error = ENXIO;
+ }
+errexit:
+ return (error);
+}
+
+/*
+ * Called if the probe succeeded and our bid won the device.
+ * We can be destructive here as we know we have the device.
+ * This is the first place we can be sure we have a softc structure.
+ * You would do ISA specific attach things here, but generically there aren't
+ * any (yay new-bus!).
+ */
+static int
+${1}_isa_attach (device_t device)
+{
+ int error;
+ struct ${1}_softc *scp = DEVICE2SOFTC(device);
+
+ error = ${1}_attach(device, scp);
+ if (error)
+ ${1}_isa_detach(device);
+ return (error);
+}
+
+/*
+ * Detach the driver (e.g. module unload),
+ * call the bus independent version
+ * and undo anything we did in the ISA attach routine.
+ */
+static int
+${1}_isa_detach (device_t device)
+{
+ int error;
+ struct ${1}_softc *scp = DEVICE2SOFTC(device);
+
+ error = ${1}_detach(device, scp);
+ return (error);
+}
+
+/*
+ ***************************************
+ * PCI Attachment structures and code
+ ***************************************
+ */
+
+static int ${1}_pci_probe(device_t);
+static int ${1}_pci_attach(device_t);
+static int ${1}_pci_detach(device_t);
+
+static device_method_t ${1}_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, ${1}_pci_probe),
+ DEVMETHOD(device_attach, ${1}_pci_attach),
+ DEVMETHOD(device_detach, ${1}_pci_detach),
+ { 0, 0 }
+};
+
+static driver_t ${1}_pci_driver = {
+ "${1}",
+ ${1}_pci_methods,
+ sizeof(struct ${1}_softc),
+};
+
+DRIVER_MODULE(${1}, pci, ${1}_pci_driver, ${1}_devclass, 0, 0);
+/*
+ * Cardbus is a pci bus plus extra, so use the pci driver unless special
+ * things need to be done only in the cardbus case.
+ */
+DRIVER_MODULE(${1}, cardbus, ${1}_pci_driver, ${1}_devclass, 0, 0);
+
+static struct _pcsid
+{
+ u_int32_t type;
+ const char *desc;
+} pci_ids[] = {
+ { 0x1234abcd, "ACME PCI Widgetplus" },
+ { 0x1243fedc, "Happy moon brand RIPOFFplus" },
+ { 0x00000000, NULL }
+};
+
+/*
+ * See if this card is specifically mentioned in our list of known devices.
+ * Theoretically we might also put in a weak bid for some devices that
+ * report themselves to be some generic type of device if we can handle
+ * that generic type. (other PCI_XXX calls give that info).
+ * This would allow a specific driver to over-ride us.
+ *
+ * See the comments in the ISA section regarding returning non-positive
+ * values from probe routines.
+ */
+static int
+${1}_pci_probe (device_t device)
+{
+ u_int32_t type = pci_get_devid(device);
+ struct _pcsid *ep =pci_ids;
+
+ while (ep->type && ep->type != type)
+ ++ep;
+ if (ep->desc) {
+ device_set_desc(device, ep->desc);
+ return 0; /* If there might be a better driver, return -2 */
+ } else
+ return ENXIO;
+}
+
+static int
+${1}_pci_attach(device_t device)
+{
+ int error;
+ struct ${1}_softc *scp = DEVICE2SOFTC(device);
+
+ error = ${1}_attach(device, scp);
+ if (error)
+ ${1}_pci_detach(device);
+ return (error);
+}
+
+static int
+${1}_pci_detach (device_t device)
+{
+ int error;
+ struct ${1}_softc *scp = DEVICE2SOFTC(device);
+
+ error = ${1}_detach(device, scp);
+ return (error);
+}
+
+/*
+ ****************************************
+ * Common Attachment sub-functions
+ ****************************************
+ */
+static int
+${1}_attach(device_t device, struct ${1}_softc * scp)
+{
+ device_t parent = device_get_parent(device);
+ int unit = device_get_unit(device);
+
+ scp->dev = make_dev(&${1}_cdevsw, 0,
+ UID_ROOT, GID_OPERATOR, 0600, "${1}%d", unit);
+ scp->dev->si_drv1 = scp;
+
+ if (${1}_allocate_resources(device))
+ goto errexit;
+
+ scp->bt = rman_get_bustag(scp->res_ioport);
+ scp->bh = rman_get_bushandle(scp->res_ioport);
+
+ /* Register the interrupt handler. */
+ /*
+ * The type should be one of:
+ * INTR_TYPE_TTY
+ * INTR_TYPE_BIO
+ * INTR_TYPE_CAM
+ * INTR_TYPE_NET
+ * INTR_TYPE_MISC
+ * This will probably change with SMPng. INTR_TYPE_FAST may be
+ * OR'd into this type to mark the interrupt fast. However, fast
+ * interrupts cannot be shared at all so special precautions are
+ * necessary when coding fast interrupt routines.
+ */
+ if (scp->res_irq) {
+ /* Default to the tty mask for registration. */ /* XXX */
+ if (BUS_SETUP_INTR(parent, device, scp->res_irq, INTR_TYPE_TTY,
+ ${1}intr, scp, &scp->intr_cookie) == 0) {
+ /* Do something if successful. */
+ } else
+ goto errexit;
+ }
+
+ /*
+ * If we want to access the memory we will need
+ * to know where it was mapped.
+ *
+ * Use of this function is discouraged, however. You should
+ * be accessing the device with the bus_space API if at all
+ * possible.
+ */
+ scp->vaddr = rman_get_virtual(scp->res_memory);
+ return 0;
+
+errexit:
+ /*
+ * Undo anything we may have done.
+ */
+ ${1}_detach(device, scp);
+ return (ENXIO);
+}
+
+static int
+${1}_detach(device_t device, struct ${1}_softc *scp)
+{
+ device_t parent = device_get_parent(device);
+
+ /*
+ * At this point stick a strong piece of wood into the device
+ * to make sure it is stopped safely. The alternative is to
+ * simply REFUSE to detach if it's busy. What you do depends on
+ * your specific situation.
+ *
+ * Sometimes the parent bus will detach you anyway, even if you
+ * are busy. You must cope with that possibility. Your hardware
+ * might even already be gone in the case of cardbus or pccard
+ * devices.
+ */
+ /* ZAP some register */
+
+ /*
+ * Take our interrupt handler out of the list of handlers
+ * that can handle this irq.
+ */
+ if (scp->intr_cookie != NULL) {
+ if (BUS_TEARDOWN_INTR(parent, device,
+ scp->res_irq, scp->intr_cookie) != 0)
+ printf("intr teardown failed.. continuing\n");
+ scp->intr_cookie = NULL;
+ }
+
+ /*
+ * Deallocate any system resources we may have
+ * allocated on behalf of this driver.
+ */
+ scp->vaddr = NULL;
+ return ${1}_deallocate_resources(device);
+}
+
+static int
+${1}_allocate_resources(device_t device)
+{
+ int error;
+ struct ${1}_softc *scp = DEVICE2SOFTC(device);
+ int size = 16; /* SIZE of port range used. */
+
+ scp->res_ioport = bus_alloc_resource(device, SYS_RES_IOPORT,
+ &scp->rid_ioport, 0ul, ~0ul, size, RF_ACTIVE);
+ if (scp->res_ioport == NULL)
+ goto errexit;
+
+ scp->res_irq = bus_alloc_resource(device, SYS_RES_IRQ,
+ &scp->rid_irq, 0ul, ~0ul, 1, RF_SHAREABLE|RF_ACTIVE);
+ if (scp->res_irq == NULL)
+ goto errexit;
+
+ scp->res_drq = bus_alloc_resource(device, SYS_RES_DRQ,
+ &scp->rid_drq, 0ul, ~0ul, 1, RF_ACTIVE);
+ if (scp->res_drq == NULL)
+ goto errexit;
+
+ scp->res_memory = bus_alloc_resource(device, SYS_RES_MEMORY,
+ &scp->rid_memory, 0ul, ~0ul, MSIZE, RF_ACTIVE);
+ if (scp->res_memory == NULL)
+ goto errexit;
+ return (0);
+
+errexit:
+ error = ENXIO;
+ /* Cleanup anything we may have assigned. */
+ ${1}_deallocate_resources(device);
+ return (ENXIO); /* For want of a better idea. */
+}
+
+static int
+${1}_deallocate_resources(device_t device)
+{
+ struct ${1}_softc *scp = DEVICE2SOFTC(device);
+
+ if (scp->res_irq != 0) {
+ bus_deactivate_resource(device, SYS_RES_IRQ,
+ scp->rid_irq, scp->res_irq);
+ bus_release_resource(device, SYS_RES_IRQ,
+ scp->rid_irq, scp->res_irq);
+ scp->res_irq = 0;
+ }
+ if (scp->res_ioport != 0) {
+ bus_deactivate_resource(device, SYS_RES_IOPORT,
+ scp->rid_ioport, scp->res_ioport);
+ bus_release_resource(device, SYS_RES_IOPORT,
+ scp->rid_ioport, scp->res_ioport);
+ scp->res_ioport = 0;
+ }
+ if (scp->res_memory != 0) {
+ bus_deactivate_resource(device, SYS_RES_MEMORY,
+ scp->rid_memory, scp->res_memory);
+ bus_release_resource(device, SYS_RES_MEMORY,
+ scp->rid_memory, scp->res_memory);
+ scp->res_memory = 0;
+ }
+ if (scp->res_drq != 0) {
+ bus_deactivate_resource(device, SYS_RES_DRQ,
+ scp->rid_drq, scp->res_drq);
+ bus_release_resource(device, SYS_RES_DRQ,
+ scp->rid_drq, scp->res_drq);
+ scp->res_drq = 0;
+ }
+ if (scp->dev)
+ destroy_dev(scp->dev);
+ return (0);
+}
+
+static void
+${1}intr(void *arg)
+{
+ struct ${1}_softc *scp = (struct ${1}_softc *) arg;
+
+ /*
+ * Well we got an interrupt, now what?
+ *
+ * Make sure that the interrupt routine will always terminate,
+ * even in the face of "bogus" data from the card.
+ */
+ (void)scp; /* Delete this line after using scp. */
+ return;
+}
+
+static int
+${1}ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
+{
+ struct ${1}_softc *scp = DEV2SOFTC(dev);
+
+ (void)scp; /* Delete this line after using scp. */
+ switch (cmd) {
+ case DHIOCRESET:
+ /* Whatever resets it. */
+#if 0
+ ${UPPER}_OUTB(SOME_PORT, 0xff);
+#endif
+ break;
+ default:
+ return ENXIO;
+ }
+ return (0);
+}
+/*
+ * You also need read, write, open, close routines.
+ * This should get you started.
+ */
+static int
+${1}open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct ${1}_softc *scp = DEV2SOFTC(dev);
+
+ /*
+ * Do processing.
+ */
+ (void)scp; /* Delete this line after using scp. */
+ return (0);
+}
+
+static int
+${1}close(struct cdev *dev, int fflag, int devtype, struct thread *td)
+{
+ struct ${1}_softc *scp = DEV2SOFTC(dev);
+
+ /*
+ * Do processing.
+ */
+ (void)scp; /* Delete this line after using scp. */
+ return (0);
+}
+
+static int
+${1}read(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ struct ${1}_softc *scp = DEV2SOFTC(dev);
+ int toread;
+
+ /*
+ * Do processing.
+ * Read from buffer.
+ */
+ (void)scp; /* Delete this line after using scp. */
+ toread = (min(uio->uio_resid, sizeof(scp->buffer)));
+ return(uiomove(scp->buffer, toread, uio));
+}
+
+static int
+${1}write(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ struct ${1}_softc *scp = DEV2SOFTC(dev);
+ int towrite;
+
+ /*
+ * Do processing.
+ * Write to buffer.
+ */
+ (void)scp; /* Delete this line after using scp. */
+ towrite = (min(uio->uio_resid, sizeof(scp->buffer)));
+ return(uiomove(scp->buffer, towrite, uio));
+}
+
+static int
+${1}mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
+{
+ struct ${1}_softc *scp = DEV2SOFTC(dev);
+
+ /*
+ * Given a byte offset into your device, return the PHYSICAL
+ * page number that it would map to.
+ */
+ (void)scp; /* Delete this line after using scp. */
+#if 0 /* If we had a frame buffer or whatever... do this. */
+ if (offset > FRAMEBUFFERSIZE - PAGE_SIZE)
+ return (-1);
+ return i386_btop((FRAMEBASE + offset));
+#else
+ return (-1);
+#endif
+}
+
+static int
+${1}poll(struct cdev *dev, int which, struct thread *td)
+{
+ struct ${1}_softc *scp = DEV2SOFTC(dev);
+
+ /*
+ * Do processing.
+ */
+ (void)scp; /* Delete this line after using scp. */
+ return (0); /* This is the wrong value I'm sure. */
+}
+
+DONE
+
+cat >${TOP}/sys/${1}io.h <<DONE
+/*
+ * Definitions needed to access the ${1} device (ioctls etc)
+ * see mtio.h, ioctl.h as examples.
+ */
+#ifndef SYS_DHIO_H
+#define SYS_DHIO_H
+
+#ifndef KERNEL
+#include <sys/types.h>
+#endif
+#include <sys/ioccom.h>
+
+/*
+ * Define an ioctl here.
+ */
+#define DHIOCRESET _IO('D', 0) /* Reset the ${1} device. */
+#endif
+DONE
+
+if [ ! -d ${TOP}/modules/${1} ]; then
+ mkdir -p ${TOP}/modules/${1}
+fi
+
+cat >${TOP}/modules/${1}/Makefile <<DONE
+# ${UPPER} Loadable Kernel Module
+
+.PATH: \${.CURDIR}/../../dev/${1}
+KMOD = ${1}
+SRCS = ${1}.c
+SRCS += opt_inet.h device_if.h bus_if.h pci_if.h isa_if.h
+
+# You may need to do this is your device is an if_xxx driver.
+opt_inet.h:
+ echo "#define INET 1" > opt_inet.h
+
+.include <bsd.kmod.mk>
+DONE
+
+echo -n "Do you want to build the '${1}' module? [Y]"
+read VAL
+if [ "-z" "$VAL" ]; then
+ VAL=YES
+fi
+case ${VAL} in
+[yY]*)
+ (cd ${TOP}/modules/${1}; make depend; make )
+ ;;
+*)
+# exit
+ ;;
+esac
+
+echo ""
+echo -n "Do you want to build the '${UPPER}' kernel? [Y]"
+read VAL
+if [ "-z" "$VAL" ]; then
+ VAL=YES
+fi
+case ${VAL} in
+[yY]*)
+ (
+ cd ${TOP}/i386/conf; \
+ config ${UPPER}; \
+ cd ${TOP}/i386/compile/${UPPER}; \
+ make depend; \
+ make; \
+ )
+ ;;
+*)
+# exit
+ ;;
+esac
+
+#--------------end of script---------------
+#
+# Edit to your taste...
+#
+#
diff --git a/share/examples/drivers/make_pseudo_driver.sh b/share/examples/drivers/make_pseudo_driver.sh
new file mode 100644
index 000000000000..5d6d09aa9648
--- /dev/null
+++ b/share/examples/drivers/make_pseudo_driver.sh
@@ -0,0 +1,435 @@
+#!/bin/sh
+# This writes a skeleton driver and puts it into the kernel tree for you
+#
+# arg1 is lowercase "foo"
+# arg2 path to the kernel sources, "/sys" if omitted
+#
+# Trust me, RUN THIS SCRIPT :)
+#
+#
+#-------cut here------------------
+
+if [ "${1}X" = "X" ]
+then
+ echo "Hey , how about some help here.. give me a device name!"
+ exit 1
+fi
+if [ "X${2}" = "X" ]; then
+ TOP=`cd /sys; pwd -P`
+ echo "Using ${TOP} as the path to the kernel sources!"
+else
+ TOP=${2}
+fi
+
+for i in "" "conf" "i386" "i386/conf" "dev" "sys" "modules"
+do
+ if [ -d ${TOP}/${i} ]
+ then
+ continue
+ fi
+ echo "${TOP}/${i}: no such directory."
+ echo "Please, correct the error and try again."
+ exit 1
+done
+
+UPPER=`echo ${1} |tr "[:lower:]" "[:upper:]"`
+
+if [ -d ${TOP}/modules/${1} ]; then
+ echo "There appears to already be a module called ${1}"
+ echo -n "Should it be overwritten? [Y]"
+ read VAL
+ if [ "-z" "$VAL" ]; then
+ VAL=YES
+ fi
+ case ${VAL} in
+ [yY]*)
+ echo "Cleaning up from prior runs"
+ rm -rf ${TOP}/dev/${1}
+ rm -rf ${TOP}/modules/${1}
+ rm ${TOP}/conf/files.${UPPER}
+ rm ${TOP}/i386/conf/${UPPER}
+ rm ${TOP}/sys/${1}io.h
+ ;;
+ *)
+ exit 1
+ ;;
+ esac
+fi
+
+echo "The following files will be created:"
+echo ${TOP}/modules/${1}
+echo ${TOP}/conf/files.${UPPER}
+echo ${TOP}/i386/conf/${UPPER}
+echo ${TOP}/dev/${1}
+echo ${TOP}/dev/${1}/${1}.c
+echo ${TOP}/sys/${1}io.h
+echo ${TOP}/modules/${1}
+echo ${TOP}/modules/${1}/Makefile
+
+mkdir ${TOP}/modules/${1}
+
+cat >${TOP}/conf/files.${UPPER} <<DONE
+dev/${1}/${1}.c optional ${1}
+DONE
+
+cat >${TOP}/i386/conf/${UPPER} <<DONE
+# Configuration file for kernel type: ${UPPER}
+
+files "${TOP}/conf/files.${UPPER}"
+
+include GENERIC
+
+ident ${UPPER}
+
+# trust me, you'll need this
+options KDB
+options DDB
+device ${1}
+DONE
+
+if [ ! -d ${TOP}/dev/${1} ]; then
+ mkdir -p ${TOP}/dev/${1}
+fi
+
+cat >${TOP}/dev/${1}/${1}.c <<DONE
+/*
+ * Copyright (c) [year] [your name]
+ *
+ * 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.
+ *
+ * ${1} driver
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h> /* SYSINIT stuff */
+#include <sys/uio.h> /* SYSINIT stuff */
+#include <sys/conf.h> /* cdevsw stuff */
+#include <sys/malloc.h> /* malloc region definitions */
+#include <sys/proc.h>
+#include <sys/${1}io.h> /* ${1} IOCTL definitions */
+
+#include <machine/clock.h> /* DELAY() */
+
+#define N${UPPER} 3 /* defines number of instances */
+
+/* XXX These should be defined in terms of bus-space ops. */
+#define ${UPPER}_INB(port) inb(port)
+#define ${UPPER}_OUTB(port, val) (port, (val))
+
+/* Function prototypes (these should all be static) */
+static d_open_t ${1}open;
+static d_close_t ${1}close;
+static d_read_t ${1}read;
+static d_write_t ${1}write;
+static d_ioctl_t ${1}ioctl;
+static d_mmap_t ${1}mmap;
+static d_poll_t ${1}poll;
+
+#define CDEV_MAJOR 20
+static struct cdevsw ${1}_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = ${1}open,
+ .d_close = ${1}close,
+ .d_read = ${1}read,
+ .d_write = ${1}write,
+ .d_ioctl = ${1}ioctl,
+ .d_poll = ${1}poll,
+ .d_mmap = ${1}mmap,
+ .d_name = "${1}",
+};
+
+/*
+ * device specific Misc defines
+ */
+#define BUFFERSIZE 1024
+#define UNIT(dev) dev2unit(dev) /* assume one minor number per unit */
+
+/*
+ * One of these per allocated device
+ */
+struct ${1}_softc {
+ u_long iobase;
+ char buffer[BUFFERSIZE];
+ struct cdev *dev;
+};
+
+typedef struct ${1}_softc *sc_p;
+
+static sc_p sca[N${UPPER}];
+
+/*
+ * Macro to check that the unit number is valid
+ * Often this isn't needed as once the open() is performed,
+ * the unit number is pretty much safe.. The exception would be if we
+ * implemented devices that could "go away". in which case all these routines
+ * would be wise to check the number, DIAGNOSTIC or not.
+ */
+#define CHECKUNIT(RETVAL) \
+do { /* the do-while is a safe way to do this grouping */ \
+ if (unit > N${UPPER}) { \
+ printf("%s: bad unit %d\n", __func__, unit); \
+ return (RETVAL); \
+ } \
+ if (scp == NULL) { \
+ printf("%s: unit %d not attached\n", __func__, unit); \
+ return (RETVAL); \
+ } \
+} while (0)
+
+#ifdef DIAGNOSTIC
+#define CHECKUNIT_DIAG(RETVAL) CHECKUNIT(RETVAL)
+#else /* DIAGNOSTIC */
+#define CHECKUNIT_DIAG(RETVAL)
+#endif /* DIAGNOSTIC */
+
+static int
+${1}ioctl (struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
+{
+ int unit = UNIT(dev);
+ sc_p scp = sca[unit];
+
+ CHECKUNIT_DIAG(ENXIO);
+
+ switch (cmd) {
+ case DHIOCRESET:
+ /* whatever resets it */
+ (void)scp; /* Delete this line after using scp. */
+#if 0
+ ${UPPER}_OUTB(scp->iobase, 0xff);
+#endif
+ break;
+ default:
+ return ENXIO;
+ }
+ return (0);
+}
+
+/*
+ * You also need read, write, open, close routines.
+ * This should get you started
+ */
+static int
+${1}open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ int unit = UNIT(dev);
+ sc_p scp = sca[unit];
+
+ CHECKUNIT(ENXIO);
+
+ (void)scp; /* Delete this line after using scp. */
+ /*
+ * Do processing
+ */
+ return (0);
+}
+
+static int
+${1}close(struct cdev *dev, int fflag, int devtype, struct thread *td)
+{
+ int unit = UNIT(dev);
+ sc_p scp = sca[unit];
+
+ CHECKUNIT_DIAG(ENXIO);
+
+ (void)scp; /* Delete this line after using scp. */
+ /*
+ * Do processing
+ */
+ return (0);
+}
+
+static int
+${1}read(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ int unit = UNIT(dev);
+ sc_p scp = sca[unit];
+ int toread;
+
+
+ CHECKUNIT_DIAG(ENXIO);
+
+ /*
+ * Do processing
+ * read from buffer
+ */
+ toread = (min(uio->uio_resid, sizeof(scp->buffer)));
+ return(uiomove(scp->buffer, toread, uio));
+}
+
+static int
+${1}write(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ int unit = UNIT(dev);
+ sc_p scp = sca[unit];
+ int towrite;
+
+ CHECKUNIT_DIAG(ENXIO);
+
+ /*
+ * Do processing
+ * write to buffer
+ */
+ towrite = (min(uio->uio_resid, sizeof(scp->buffer)));
+ return(uiomove(scp->buffer, towrite, uio));
+}
+
+static int
+${1}mmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
+{
+ int unit = UNIT(dev);
+ sc_p scp = sca[unit];
+
+ CHECKUNIT_DIAG(-1);
+
+ (void)scp; /* Delete this line after using scp. */
+ /*
+ * Do processing
+ */
+#if 0 /* if we had a frame buffer or whatever.. do this */
+ if (offset > FRAMEBUFFERSIZE - PAGE_SIZE) {
+ return (-1);
+ }
+ return i386_btop((FRAMEBASE + offset));
+#else
+ return (-1);
+#endif
+}
+
+static int
+${1}poll(struct cdev *dev, int which, struct thread *td)
+{
+ int unit = UNIT(dev);
+ sc_p scp = sca[unit];
+
+ CHECKUNIT_DIAG(ENXIO);
+
+ (void)scp; /* Delete this line after using scp. */
+ /*
+ * Do processing
+ */
+ return (0); /* this is the wrong value I'm sure */
+}
+
+/*
+ * Now for some driver initialisation.
+ * Occurs ONCE during boot (very early).
+ */
+static void
+${1}_drvinit(void *unused)
+{
+ int unit;
+ sc_p scp;
+
+ for (unit = 0; unit < N${UPPER}; unit++) {
+ /*
+ * Allocate storage for this instance .
+ */
+ scp = malloc(sizeof(*scp), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if( scp == NULL) {
+ printf("${1}%d failed to allocate strorage\n", unit);
+ return;
+ }
+ sca[unit] = scp;
+ scp->dev = make_dev(&${1}_cdevsw, unit,
+ UID_ROOT, GID_KMEM, 0640, "${1}%d", unit);
+ }
+}
+
+SYSINIT(${1}dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE+CDEV_MAJOR,
+ ${1}_drvinit, NULL);
+DONE
+
+cat >${TOP}/sys/${1}io.h <<DONE
+/*
+ * Definitions needed to access the ${1} device (ioctls etc)
+ * see mtio.h , ioctl.h as examples
+ */
+#ifndef SYS_DHIO_H
+#define SYS_DHIO_H
+
+#ifndef KERNEL
+#include <sys/types.h>
+#endif
+#include <sys/ioccom.h>
+
+/*
+ * define an ioctl here
+ */
+#define DHIOCRESET _IO('D', 0) /* reset the ${1} device */
+#endif
+DONE
+
+if [ ! -d ${TOP}/modules/${1} ]; then
+ mkdir -p ${TOP}/modules/${1}
+fi
+
+cat >${TOP}/modules/${1}/Makefile <<DONE
+# ${UPPER} Loadable Kernel Module
+
+.PATH: \${.CURDIR}/../../dev/${1}
+KMOD = ${1}
+SRCS = ${1}.c
+
+.include <bsd.kmod.mk>
+DONE
+
+echo -n "Do you want to build the '${1}' module? [Y]"
+read VAL
+if [ "-z" "$VAL" ]; then
+ VAL=YES
+fi
+case ${VAL} in
+[yY]*)
+ (cd ${TOP}/modules/${1}; make depend; make )
+ ;;
+*)
+# exit
+ ;;
+esac
+
+echo ""
+echo -n "Do you want to build the '${UPPER}' kernel? [Y]"
+read VAL
+if [ "-z" "$VAL" ]; then
+ VAL=YES
+fi
+case ${VAL} in
+[yY]*)
+ (
+ cd ${TOP}/i386/conf; \
+ config ${UPPER}; \
+ cd ${TOP}/i386/compile/${UPPER}; \
+ make depend; \
+ make; \
+ )
+ ;;
+*)
+# exit
+ ;;
+esac
+
+#--------------end of script---------------
+#
+#edit to your taste..
+#
+#
diff --git a/share/examples/etc/README.examples b/share/examples/etc/README.examples
new file mode 100644
index 000000000000..b0dc2b83ad66
--- /dev/null
+++ b/share/examples/etc/README.examples
@@ -0,0 +1,69 @@
+
+The /usr/share/examples/etc directory contains the original
+distribution versions of the files which are shipped in /etc. This is
+intended to make it easy to recover when the /etc versions are
+accidentally deleted or broken beyond repair.
+
+This directory contains the following files:
+
+amd.map - filesystem automounter lookup resolution map (see amd(8))
+apmd.conf - configuration file for apmd(8)
+bsd-style-copyright - copyright style for bsd system
+crontab - system scheduled command table (see crontab(5))
+csh.cshrc - sample .cshrc (see csh(1))
+csh.login - sample .login
+csh.logout - sample .logout
+defaults/ - directory containing default configuration file
+devd.conf - configuration file for devd(8)
+devfs.conf - configuration file for devfs(8)
+dhclient.conf - configuration file for dhclient(8)
+disktab - disk description file (see disktab(5))
+fbtab - configuration file for login(1)
+ftpusers - user restriction file for ftpd(8)
+gettytab - defines port configuration for getty(8)
+group - group permissions file (see group(5))
+hosts - see hosts(5)
+hosts.allow - defines allow trusted hosts
+hosts.equiv - defines system-wide trusted hosts (see ruserok(3))
+hosts.lpd - defines trusted hosts for lpd(8)
+inetd.conf - configuration file for inetd(8)
+locate.rc - configuration file for locate(1)
+login.access - configuration file for login(8) (see login.access(5))
+login.conf - login class capabilities database (see login.conf(5))
+mac.conf - TrustedBSD MAC userland policy configuration file
+mail.rc - systemwide initialization files for mail(1)
+make.conf - example configuration variables for system builds
+motd - sample Message of the Day
+netconfig - network configuration data base
+netstart - network startup script run from /etc/rc
+network.subr - routines for network configuration scripts
+networks - see networks(5)
+newsyslog.conf - configuration for system log file rotator newsyslog(8)
+nsmb.conf - smbfs lookups configuration file
+pf.conf - pf(4) example configuration file
+pf.os - SYN fingerprint database
+phones - phone number database for tip(1)
+printcap - configuration file for lpr(1)
+profile - system-wide .profile for sh(1)
+protocols - see protocols(5)
+rc - system startup script (see init(8))
+rc.bsdextended - startup policy for the mac_bsdextended(4) security module.
+rc.firewall - ipfw(8) setup script with basic rulesets
+rc.initdiskless - configuration file to boot a diskless machine
+rc.resume - sample run command file for APM Resume Event
+rc.shutdown - system shutdown script (see init(8))
+rc.subr - script with functions used by various rc scripts
+rc.suspend - sample run command file for APM Resume Event
+remote - configuration file for tip(1)
+rpc - see rpc(5)
+security - script run from crontab to do nightly security checks
+services - see services(5)
+shells - list of configurable shells (see shells(5))
+snmpd.config - example configuration file for bsnmpd(1)
+sysctl.conf - configuration file for sysctl(8)
+syslog.conf - configuration file for syslogd(8)
+ttys - defines port configuration for init(8)
+defaults/bluetooth.device.conf -
+defaults/devfs.rules - default configuration rules for devfs(8)
+defaults/periodic.conf - default configuration file for periodic(8)
+defaults/rc.conf - default system configuration info (see rc.conf(5))
diff --git a/share/examples/etc/bsd-style-copyright b/share/examples/etc/bsd-style-copyright
new file mode 100644
index 000000000000..5822943b54eb
--- /dev/null
+++ b/share/examples/etc/bsd-style-copyright
@@ -0,0 +1,28 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) [year] [your name]
+ *
+ * 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.
+ *
+ * [id for your version control system, if any]
+ */
diff --git a/share/examples/etc/make.conf b/share/examples/etc/make.conf
new file mode 100644
index 000000000000..0cf156371aec
--- /dev/null
+++ b/share/examples/etc/make.conf
@@ -0,0 +1,280 @@
+#
+# NOTE: Please would any committer updating this file also update the
+# make.conf(5) manual page, if necessary, which is located in
+# src/share/man/man5/make.conf.5.
+#
+# /etc/make.conf, if present, will be read by make (see
+# /usr/share/mk/sys.mk). It allows you to override macro definitions
+# to make without changing your source tree, or anything the source
+# tree installs.
+#
+# This file must be in valid Makefile syntax.
+#
+# There are additional things you can put into /etc/make.conf.
+# You have to find those in the Makefiles and documentation of
+# the source tree.
+#
+# Note, that you should not set MAKEOBJDIRPREFIX or MAKEOBJDIR
+# from make.conf (or as command line variables to make).
+# Both variables are environment variables for make and must be used as:
+#
+# env MAKEOBJDIRPREFIX=/big/directory make
+#
+#
+# The CPUTYPE variable controls which processor should be targeted for
+# generated code. This controls processor-specific optimizations in
+# certain code (currently only OpenSSL) as well as modifying the value
+# of CFLAGS to contain the appropriate optimization directive to cc.
+# The automatic setting of CFLAGS may be overridden using the
+# NO_CPU_CFLAGS variable below.
+# Currently the following CPU types are recognized:
+# Intel x86 architecture:
+# (AMD CPUs) znver4, znver3, znver2, znver1, bdver4, bdver3, bdver2,
+# bdver1, btver2, btver1, amdfam10, opteron-sse3,
+# athlon64-sse3, k8-sse3, opteron, athlon64, athlon-fx,
+# k8, athlon-mp, athlon-xp, athlon-4, athlon-tbird,
+# athlon, k7, geode, k6-3, k6-2, k6
+# (Intel CPUs) alderlake, sapphirerapids, tigerlake, cooperlake,
+# cascadelake, tremont, goldmont-plus, icelake-server,
+# icelake-client, cannonlake, knm, skylake-avx512, knl,
+# goldmont, skylake, broadwell, haswell, ivybridge,
+# sandybridge, westmere, nehalem, silvermont, bonnell,
+# core2, core, nocona, pentium4m, pentium4, prescott,
+# pentium3m, pentium3, pentium-m, pentium2, pentiumpro,
+# pentium-mmx, pentium, i486
+# (VIA CPUs) c7, c3-2, c3
+# ARM architecture: armv5, armv5te, armv6, armv6t2, arm1176jzf-s, armv7,
+# armv7-a, armv7ve, generic-armv7-a, cortex-a5,
+# cortex-a7, cortex-a8, cortex-a9, cortex-a12,
+# cortex-a15, cortex-a17
+# ARM64 architecture: cortex-a53, cortex-a57, cortex-a72,
+# exynos-m1
+#
+# (?= allows to buildworld for a different CPUTYPE.)
+#
+#CPUTYPE?=pentium3
+#NO_CPU_CFLAGS= # Don't add -march=<cpu> to CFLAGS automatically
+#
+# CFLAGS controls the compiler settings used when compiling C code.
+# Note that optimization settings other than -O and -O2 are not recommended
+# or supported for compiling the world or the kernel - please revert any
+# nonstandard optimization settings
+# before submitting bug reports without patches to the developers.
+#
+# CFLAGS.arch provides a mechanism for applying CFLAGS only when building
+# the given architecture. This is useful primarily on a system used for
+# cross-building, when you have a set of flags to apply to the TARGET_ARCH
+# being cross-built but don't want those settings applied to building the
+# cross-tools or other components that run on the build host machine.
+#
+# CXXFLAGS controls the compiler settings used when compiling C++ code.
+# Note that CXXFLAGS is initially set to the value of CFLAGS. If you wish
+# to add to CXXFLAGS value, "+=" must be used rather than "=". Using "="
+# alone will remove the often needed contents of CFLAGS from CXXFLAGS.
+#
+# Additional compiler flags can be specified that extend or override
+# default ones. However, neither the base system nor ports are guaranteed
+# to build and function without problems with non-default settings.
+#
+# CFLAGS+= -msse3
+# CXXFLAGS+= -msse3
+# CFLAGS.armv6+= -mfloat-abi=softfp
+#
+# MAKE_SHELL controls the shell used internally by make(1) to process the
+# command scripts in makefiles. Three shells are supported, sh, ksh, and
+# csh. Using sh is most common, and advised. Using ksh *may* work, but is
+# not guaranteed to. Using csh is absurd. The default is to use sh.
+#
+#MAKE_SHELL?=sh
+#
+# BDECFLAGS are a set of gcc warning settings that Bruce Evans has suggested
+# for use in developing FreeBSD and testing changes. They can be used by
+# putting "CFLAGS+=${BDECFLAGS}" in /etc/make.conf. -Wconversion is not
+# included here due to compiler bugs, e.g., mkdir()'s mode_t argument.
+#
+#BDECFLAGS= -W -Wall -ansi -pedantic -Wbad-function-cast -Wcast-align \
+# -Wcast-qual -Wchar-subscripts -Winline \
+# -Wmissing-prototypes -Wnested-externs -Wpointer-arith \
+# -Wredundant-decls -Wshadow -Wstrict-prototypes -Wwrite-strings
+#
+# To compile just the kernel with special optimizations, you should use
+# this instead of CFLAGS (which is not applicable to kernel builds anyway).
+# There is very little to gain by using higher optimization levels, and doing
+# so can cause problems.
+#
+#COPTFLAGS= -O -pipe
+#
+# Compare before install.
+#INSTALL+= -C
+#
+# Mtree will follow symlinks.
+#MTREE_FOLLOWS_SYMLINKS= -L
+#
+# To enable installing newgrp(1) with the setuid bit turned on.
+# Without the setuid bit, newgrp cannot change users' groups.
+#ENABLE_SUID_NEWGRP=
+#
+# To avoid building various parts of the base system:
+#NO_MODULES= # do not build modules with the kernel
+#NO_SHARE= # do not go into the share subdir
+#NO_SHARED= # build /bin and /sbin statically linked (bad idea)
+#
+# Variables that control how ppp(8) is built.
+#PPP_NO_NAT= # do not build with NAT support (see make.conf(5))
+#PPP_NO_NETGRAPH= # do not build with Netgraph support
+#PPP_NO_RADIUS= # do not build with RADIUS support
+#PPP_NO_SUID= # build with normal permissions
+#
+#TRACEROUTE_NO_IPSEC= # do not build traceroute(8) with IPSEC support
+#
+# To build sys/modules when building the world (our old way of doing things).
+#MODULES_WITH_WORLD= # do not build modules when building kernel
+#
+# The list of modules to build instead of all of them.
+#MODULES_OVERRIDE= linux ipfw
+#
+# The list of modules to never build, applied *after* MODULES_OVERRIDE.
+#WITHOUT_MODULES= plip
+#
+# If you do not want unformatted manual pages to be compressed
+# when they are installed:
+#
+#WITHOUT_MANCOMPRESS=t
+#
+#
+# Default format for system documentation in share/doc, depends on
+# your printer. Set this to "ascii" for simple printers or screen.
+#
+#PRINTERDEVICE= ps
+#
+#
+# How long to wait for a console keypress before booting the default kernel.
+# This value is approximately in milliseconds. Keypresses are accepted by the
+# BIOS before booting from disk, making it possible to give custom boot
+# parameters even when this is set to 0.
+#
+#BOOTWAIT=0
+#BOOTWAIT=30000
+#
+# By default, the system will always use the keyboard/video card as system
+# console. However, the boot blocks may be dynamically configured to use a
+# serial port in addition to or instead of the keyboard/video console.
+#
+# By default we use COM1 as our serial console port *if* we're going to use
+# a serial port as our console at all. Alter as necessary.
+#
+# COM1: = 0x3F8, COM2: = 0x2F8, COM3: = 0x3E8, COM4: = 0x2E8
+#
+#BOOT_COMCONSOLE_PORT= 0x3F8
+#
+# The default serial console speed is 115200. It can be set to a different
+# rate, if desired in your environment.
+#
+#BOOT_COMCONSOLE_SPEED= 9600
+#
+# By default the 'pxeboot' loader retrieves the kernel via NFS. Defining
+# this and recompiling /usr/src/stand will cause it to retrieve the kernel
+# via TFTP. This allows pxeboot to load a custom BOOTP diskless kernel yet
+# still mount the server's '/' (i.e. rather than load the server's kernel).
+#
+#LOADER_TFTP_SUPPORT= YES
+#
+#
+# Kerberos 5 su (k5su)
+# If you want to use the k5su utility, define this to have it installed
+# set-user-ID.
+#ENABLE_SUID_K5SU=
+#
+#
+# top(1) uses a hash table for the user names. The size of this hash
+# can be tuned to match the number of local users. The table size should
+# be a prime number approximately twice as large as the number of lines in
+# /etc/passwd. The default number is 20011.
+#
+#TOP_TABLE_SIZE= 101
+#
+# Documentation
+#
+# The list of languages to build and install.
+#
+#DOC_LANG= en ru
+#
+#
+# sendmail
+#
+# The following sets the default m4 configuration file to use at
+# install time. Use with caution as a make install will overwrite
+# any existing /etc/mail/sendmail.cf. Note that SENDMAIL_CF is now
+# deprecated. The value should be a fully qualified path name.
+#
+#SENDMAIL_MC=/etc/mail/myconfig.mc
+#
+# The following sets the default m4 configuration file for mail
+# submission to use at install time. Use with caution as a make
+# install will overwrite any existing /etc/mail/submit.cf. The
+# value should be a fully qualified path name.
+#
+#SENDMAIL_SUBMIT_MC=/etc/mail/mysubmit.mc
+#
+# If you need to build additional .cf files during a make buildworld,
+# include the full paths to the .mc files in SENDMAIL_ADDITIONAL_MC.
+#
+#SENDMAIL_ADDITIONAL_MC=/etc/mail/foo.mc /etc/mail/bar.mc
+#
+# The following overrides the default location for the m4 configuration
+# files used to build a .cf file from a .mc file.
+#
+#SENDMAIL_CF_DIR=/usr/local/share/sendmail/cf
+#
+# Setting the following variable modifies the flags passed to m4 when
+# building a .cf file from a .mc file. It can be used to enable
+# features disabled by default.
+#
+#SENDMAIL_M4_FLAGS=
+#
+# Setting the following variables modifies the build environment for
+# sendmail and its related utilities. For example, SASL support can be
+# added with settings such as:
+#
+# with SASLv1:
+# SENDMAIL_CFLAGS=-I/usr/local/include/sasl1 -DSASL
+# SENDMAIL_LDADD=/usr/local/lib/libsasl.so
+#
+# with SASLv2:
+# SENDMAIL_CFLAGS=-I/usr/local/include -DSASL=2
+# SENDMAIL_LDADD=/usr/local/lib/libsasl2.so
+#
+# Note: If you are using Cyrus SASL with other applications which require
+# access to the sasldb file, you should add the following to your
+# sendmail.mc file:
+#
+# define(`confDONT_BLAME_SENDMAIL',`GroupReadableSASLDBFile')
+#
+#SENDMAIL_CFLAGS=
+#SENDMAIL_LDFLAGS=
+#SENDMAIL_LDADD=
+#SENDMAIL_DPADD=
+#
+# Setting SENDMAIL_SET_USER_ID will install the sendmail binary as a
+# set-user-ID root binary instead of a set-group-ID smmsp binary and will
+# prevent the installation of /etc/mail/submit.cf.
+# This is a deprecated mode of operation. See etc/mail/README for more
+# information.
+#
+#SENDMAIL_SET_USER_ID=
+#
+# The permissions to use on alias and map databases generated using
+# /etc/mail/Makefile. Defaults to 0640.
+#
+#SENDMAIL_MAP_PERMS=
+#
+#
+# It is also possible to set variables in make.conf which will only be
+# used when compiling a specific port. For more details see make(1).
+#
+#.if ${.CURDIR:M*/irc/irssi-devel*}
+#WITH_DEBUG=YES
+#.endif
+#
+# Another approach is to use /usr/ports/ports-mgmt/portconf which has
+# its own config file for port specific options.
diff --git a/share/examples/find_interface/Makefile b/share/examples/find_interface/Makefile
new file mode 100644
index 000000000000..91ce0eb88072
--- /dev/null
+++ b/share/examples/find_interface/Makefile
@@ -0,0 +1,7 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/${PROG}
+PROG= find_interface
+MAN=
+
+.include <bsd.prog.mk>
diff --git a/share/examples/find_interface/README b/share/examples/find_interface/README
new file mode 100644
index 000000000000..4df4399cdbc7
--- /dev/null
+++ b/share/examples/find_interface/README
@@ -0,0 +1,9 @@
+This is a simple program which demonstrates how to query the kernel
+routing mechanism using only a UDP socket. Pass it a hostname on
+the command line (sorry, it doesn't parse dotted decimal) and it will
+print out an IP address which names the interface over which UDP
+packets intended for that destination would be sent.
+A more sophisticated program might use the list obtained from SIOCGIFCONF
+to match the address with an interface name, but applications programmers
+much more often need to know the address of the interface rather than
+the name.
diff --git a/share/examples/find_interface/find_interface.c b/share/examples/find_interface/find_interface.c
new file mode 100644
index 000000000000..17fe1916d2bd
--- /dev/null
+++ b/share/examples/find_interface/find_interface.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 1994, 1995 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. 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.
+ */
+
+/*
+ * This is a simple program which demonstrates how to query the kernel
+ * routing mechanism using only a UDP socket. Pass it a hostname on
+ * the command line (sorry, it doesn't parse dotted decimal) and it will
+ * print out an IP address which names the interface over which UDP
+ * packets intended for that destination would be sent.
+ * A more sophisticated program might use the list obtained from SIOCGIFCONF
+ * to match the address with an interface name, but applications programmers
+ * much more often need to know the address of the interface rather than
+ * the name.
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <sysexits.h>
+
+int
+main(int argc, char **argv)
+{
+ struct sockaddr_in local, remote;
+ struct hostent *hp;
+ int s, rv, namelen;
+
+ argc--, argv++;
+
+ if (!*argv) {
+ errx(EX_USAGE, "must supply a hostname");
+ }
+
+ hp = gethostbyname(*argv);
+ if (!hp) {
+ errx(EX_NOHOST, "cannot resolve hostname: %s", *argv);
+ }
+
+ memcpy(&remote.sin_addr, hp->h_addr_list[0], sizeof remote.sin_addr);
+ remote.sin_port = htons(60000);
+ remote.sin_family = AF_INET;
+ remote.sin_len = sizeof remote;
+
+ local.sin_addr.s_addr = htonl(INADDR_ANY);
+ local.sin_port = htons(60000);
+ local.sin_family = AF_INET;
+ local.sin_len = sizeof local;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ err(EX_OSERR, "socket");
+
+ do {
+ rv = bind(s, (struct sockaddr *)&local, sizeof local);
+ local.sin_port = htons(ntohs(local.sin_port) + 1);
+ } while(rv < 0 && errno == EADDRINUSE);
+
+ if (rv < 0)
+ err(EX_OSERR, "bind");
+
+ do {
+ rv = connect(s, (struct sockaddr *)&remote, sizeof remote);
+ remote.sin_port = htons(ntohs(remote.sin_port) + 1);
+ } while(rv < 0 && errno == EADDRINUSE);
+
+ if (rv < 0)
+ err(EX_OSERR, "connect");
+
+ namelen = sizeof local;
+ rv = getsockname(s, (struct sockaddr *)&local, &namelen);
+ if (rv < 0)
+ err(EX_OSERR, "getsockname");
+
+ printf("Route to %s is out %s\n", *argv, inet_ntoa(local.sin_addr));
+ return 0;
+}
diff --git a/share/examples/flua/libjail.lua b/share/examples/flua/libjail.lua
new file mode 100644
index 000000000000..650f0ca2c6a0
--- /dev/null
+++ b/share/examples/flua/libjail.lua
@@ -0,0 +1,105 @@
+#!/usr/libexec/flua
+--[[
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020, Ryan Moeller <freqlabs@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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+]]--
+
+jail = require("jail")
+ucl = require("ucl")
+
+name = "demo"
+
+local has_demo = false
+
+-- Make sure we don't have a demo jail to start with; "jid" and "name" are
+-- always present.
+for jparams in jail.list() do
+ if jparams["name"] == name then
+ has_demo = true
+ break
+ end
+end
+
+if not has_demo then
+ -- Create a persistent jail named "demo" with all other parameters default.
+ jid, err = jail.setparams(name, {persist = "true"}, jail.CREATE)
+ if not jid then
+ error(err)
+ end
+end
+
+-- Get a list of all known jail parameter names.
+allparams = jail.allparams()
+
+-- Get all the parameters of the jail we created.
+jid, res = jail.getparams(name, allparams)
+if not jid then
+ error(res)
+end
+
+-- Display the jail's parameters as a pretty-printed JSON object.
+print(ucl.to_json(res))
+
+-- Confirm that we still have it for now.
+has_demo = false
+for jparams in jail.list() do
+ if jparams["name"] == name then
+ has_demo = true
+ break
+ end
+end
+
+if not has_demo then
+ print("demo does not exist")
+end
+
+-- Update the "persist" parameter to "false" to remove the jail.
+jid, err = jail.setparams(name, {persist = "false"}, jail.UPDATE)
+if not jid then
+ error(err)
+end
+
+-- Verify that the jail is no longer on the system.
+local is_persistent = false
+has_demo = false
+for jparams in jail.list({"persist"}) do
+ if jparams["name"] == name then
+ has_demo = true
+ jid = jparams["jid"]
+ is_persistent = jparams["persist"] ~= "false"
+ end
+end
+
+-- In fact, it does remain until this process ends -- c'est la vie.
+if has_demo then
+ io.write("demo still exists, jid " .. jid .. ", ")
+ if is_persistent then
+ io.write("persistent\n")
+ else
+ io.write("not persistent\n")
+ end
+end
diff --git a/share/examples/hast/ucarp.sh b/share/examples/hast/ucarp.sh
new file mode 100755
index 000000000000..73253a295f53
--- /dev/null
+++ b/share/examples/hast/ucarp.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2010 The FreeBSD Foundation
+# All rights reserved.
+#
+# This software was developed by Pawel Jakub Dawidek under sponsorship from
+# the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+# Shared IP address, unused for now.
+addr="10.99.0.3"
+# Password for UCARP communication.
+pass="password"
+# First node IP and interface for UCARP communication.
+nodea_srcip="10.99.0.1"
+nodea_ifnet="bge0"
+# Second node IP and interface for UCARP communication.
+nodeb_srcip="10.99.0.2"
+nodeb_ifnet="em3"
+
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+
+vhid="1"
+upscript="/root/hast/sbin/hastd/vip-up.sh"
+downscript="/root/hast/sbin/hastd/vip-down.sh"
+
+ifconfig "${nodea_ifnet}" 2>/dev/null | grep -q "inet ${nodea_srcip} "
+if [ $? -eq 0 ]; then
+ srcip="${nodea_srcip}"
+ ifnet="${nodea_ifnet}"
+ node="node A"
+fi
+ifconfig "${nodeb_ifnet}" 2>/dev/null | grep -q "inet ${nodeb_srcip} "
+if [ $? -eq 0 ]; then
+ if [ -n "${srcip}" -o -n "${ifnet}" ]; then
+ echo "Unable to determine which node is this (both match)." >/dev/stderr
+ exit 1
+ fi
+ srcip="${nodeb_srcip}"
+ ifnet="${nodeb_ifnet}"
+ node="node B"
+fi
+if [ -z "${srcip}" -o -z "${ifnet}" ]; then
+ echo "Unable to determine which node is this (none match)." >/dev/stderr
+ exit 1
+fi
+ucarp -i ${ifnet} -s ${srcip} -v ${vhid} -a ${addr} -p ${pass} -u "${upscript}" -d "${downscript}"
diff --git a/share/examples/hast/ucarp_down.sh b/share/examples/hast/ucarp_down.sh
new file mode 100755
index 000000000000..133d35c59d5b
--- /dev/null
+++ b/share/examples/hast/ucarp_down.sh
@@ -0,0 +1,99 @@
+#!/bin/sh
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2010 The FreeBSD Foundation
+# All rights reserved.
+#
+# This software was developed by Pawel Jakub Dawidek under sponsorship from
+# the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+# Resource name as defined in /etc/hast.conf.
+resource="test"
+# Supported file system types: UFS, ZFS
+fstype="UFS"
+# ZFS pool name. Required only when fstype == ZFS.
+pool="test"
+# File system mount point. Required only when fstype == UFS.
+mountpoint="/mnt/test"
+# Name of HAST provider as defined in /etc/hast.conf.
+# Required only when fstype == UFS.
+device="/dev/hast/${resource}"
+
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+
+# KIll UP script if it still runs in the background.
+sig="TERM"
+for i in `jot 30`; do
+ pgid=`pgrep -f ucarp_up.sh | head -1`
+ [ -n "${pgid}" ] || break
+ kill -${sig} -- -${pgid}
+ sig="KILL"
+ sleep 1
+done
+if [ -n "${pgid}" ]; then
+ logger -p local0.error -t hast "UCARP UP process for resource ${resource} is still running after 30 seconds."
+ exit 1
+fi
+logger -p local0.debug -t hast "UCARP UP is not running."
+
+case "${fstype}" in
+UFS)
+ mount | egrep -q "^${device} on "
+ if [ $? -eq 0 ]; then
+ # Forcibly unmount file system.
+ out=`umount -f "${mountpoint}" 2>&1`
+ if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "Unable to unmount file system for resource ${resource}: ${out}."
+ exit 1
+ fi
+ logger -p local0.debug -t hast "File system for resource ${resource} unmounted."
+ fi
+ ;;
+ZFS)
+ zpool list | egrep -q "^${pool} "
+ if [ $? -eq 0 ]; then
+ # Forcibly export file pool.
+ out=`zpool export -f "${pool}" 2>&1`
+ if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "Unable to export pool for resource ${resource}: ${out}."
+ exit 1
+ fi
+ logger -p local0.debug -t hast "ZFS pool for resource ${resource} exported."
+ fi
+ ;;
+esac
+
+# Change role to secondary for our resource.
+out=`hastctl role secondary "${resource}" 2>&1`
+if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "Unable to change to role to secondary for resource ${resource}: ${out}."
+ exit 1
+fi
+logger -p local0.debug -t hast "Role for resource ${resource} changed to secondary."
+
+logger -p local0.info -t hast "Successfully switched to secondary for resource ${resource}."
+
+exit 0
diff --git a/share/examples/hast/ucarp_up.sh b/share/examples/hast/ucarp_up.sh
new file mode 100755
index 000000000000..9f22b4205909
--- /dev/null
+++ b/share/examples/hast/ucarp_up.sh
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2010 The FreeBSD Foundation
+# All rights reserved.
+#
+# This software was developed by Pawel Jakub Dawidek under sponsorship from
+# the FreeBSD Foundation.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+# Resource name as defined in /etc/hast.conf.
+resource="test"
+# Supported file system types: UFS, ZFS
+fstype="UFS"
+# ZFS pool name. Required only when fstype == ZFS.
+pool="test"
+# File system mount point. Required only when fstype == UFS.
+mountpoint="/mnt/test"
+# Name of HAST provider as defined in /etc/hast.conf.
+device="/dev/hast/${resource}"
+
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
+
+# If there is secondary worker process, it means that remote primary process is
+# still running. We have to wait for it to terminate.
+for i in `jot 30`; do
+ pgrep -f "hastd: ${resource} \(secondary\)" >/dev/null 2>&1 || break
+ sleep 1
+done
+if pgrep -f "hastd: ${resource} \(secondary\)" >/dev/null 2>&1; then
+ logger -p local0.error -t hast "Secondary process for resource ${resource} is still running after 30 seconds."
+ exit 1
+fi
+logger -p local0.debug -t hast "Secondary process in not running."
+
+# Change role to primary for our resource.
+out=`hastctl role primary "${resource}" 2>&1`
+if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "Unable to change to role to primary for resource ${resource}: ${out}."
+ exit 1
+fi
+# Wait few seconds for provider to appear.
+for i in `jot 50`; do
+ [ -c "${device}" ] && break
+ sleep 0.1
+done
+if [ ! -c "${device}" ]; then
+ logger -p local0.error -t hast "Device ${device} didn't appear."
+ exit 1
+fi
+logger -p local0.debug -t hast "Role for resource ${resource} changed to primary."
+
+case "${fstype}" in
+UFS)
+ # Check the file system.
+ fsck -y -t ufs "${device}" >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "File system check for resource ${resource} failed."
+ exit 1
+ fi
+ logger -p local0.debug -t hast "File system check for resource ${resource} finished."
+ # Mount the file system.
+ out=`mount -t ufs "${device}" "${mountpoint}" 2>&1`
+ if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "File system mount for resource ${resource} failed: ${out}."
+ exit 1
+ fi
+ logger -p local0.debug -t hast "File system for resource ${resource} mounted."
+ ;;
+ZFS)
+ # Import ZFS pool. Do it forcibly as it remembers hostid of
+ # the other cluster node.
+ out=`zpool import -f "${pool}" 2>&1`
+ if [ $? -ne 0 ]; then
+ logger -p local0.error -t hast "ZFS pool import for resource ${resource} failed: ${out}."
+ exit 1
+ fi
+ logger -p local0.debug -t hast "ZFS pool for resource ${resource} imported."
+ ;;
+esac
+
+logger -p local0.info -t hast "Successfully switched to primary for resource ${resource}."
+
+exit 0
diff --git a/share/examples/hast/vip-down.sh b/share/examples/hast/vip-down.sh
new file mode 100755
index 000000000000..d4a6eed24f0d
--- /dev/null
+++ b/share/examples/hast/vip-down.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+
+/root/hast/sbin/hastd/ucarp_down.sh
+exit 0
diff --git a/share/examples/hast/vip-up.sh b/share/examples/hast/vip-up.sh
new file mode 100755
index 000000000000..84b6e6a94100
--- /dev/null
+++ b/share/examples/hast/vip-up.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+set -m
+/root/hast/sbin/hastd/ucarp_up.sh &
+set +m
+exit 0
diff --git a/share/examples/hwpmc/Makefile b/share/examples/hwpmc/Makefile
new file mode 100644
index 000000000000..fcbb6160bb00
--- /dev/null
+++ b/share/examples/hwpmc/Makefile
@@ -0,0 +1,10 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/hwpmc
+PROG= overhead
+LDFLAGS+= -lpmc
+MAN=
+
+install:
+
+.include <bsd.prog.mk>
diff --git a/share/examples/hwpmc/README b/share/examples/hwpmc/README
new file mode 100644
index 000000000000..f94ef2c7ecdd
--- /dev/null
+++ b/share/examples/hwpmc/README
@@ -0,0 +1,5 @@
+
+Examples illustrating the use of the hwpmc(4) driver and pmc(3)
+library interface.
+
+
diff --git a/share/examples/hwpmc/overhead.c b/share/examples/hwpmc/overhead.c
new file mode 100644
index 000000000000..bf8e060ef5b6
--- /dev/null
+++ b/share/examples/hwpmc/overhead.c
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 2014, Neville-Neil Consulting
+ * 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.
+ *
+ * Author: George V. Neville-Neil
+ *
+ */
+
+/*
+ * Calculate the time overhead of starting, stopping, and recording
+ * pmc counters.
+ *
+ * The only argument is a counter name, such as "instruction-retired"
+ * which is CPU dependent and can be found with pmmcontrol(8) using
+ * pmccontrol -L.
+ *
+ * The start, stop, read and write operations are timed using the
+ * rdtsc() macro which reads the Time Stamp Counter on the CPU.
+ */
+
+#include <stdio.h>
+#include <err.h>
+#include <sysexits.h>
+#include <sys/types.h>
+#include <machine/cpufunc.h>
+#include <pmc.h>
+
+int
+main(int argc, char **argv)
+{
+ pmc_id_t pmcid;
+ pmc_value_t read_value;
+ pmc_value_t read_clear_value;
+ uint64_t tsc1, write_cyc, start_cyc, read_cyc, stop_cyc;
+ char *counter_name;
+
+ if (argc != 2)
+ err(EX_USAGE, "counter-name required");
+
+ counter_name = argv[1];
+
+ if (pmc_init() != 0)
+ err(EX_OSERR, "hwpmc(4) not loaded, kldload or update your kernel");
+
+ if (pmc_allocate(counter_name, PMC_MODE_SC, 0, 0, &pmcid, 64*1024) < 0)
+ err(EX_OSERR, "failed to allocate %s as a system counter in counting mode",
+ counter_name);
+
+ tsc1 = rdtsc();
+ if (pmc_write(pmcid, 0) < 0)
+ err(EX_OSERR, "failed to zero counter %s", counter_name);
+ write_cyc = rdtsc() - tsc1;
+
+ tsc1 = rdtsc();
+ if (pmc_start(pmcid) < 0)
+ err(EX_OSERR, "failed to start counter %s", counter_name);
+ start_cyc = rdtsc() - tsc1;
+
+ tsc1 = rdtsc();
+ if (pmc_read(pmcid, &read_value) < 0)
+ err(EX_OSERR, "failed to read counter %s", counter_name);
+ read_cyc = rdtsc() - tsc1;
+
+ tsc1 = rdtsc();
+ if (pmc_stop(pmcid) < 0)
+ err(EX_OSERR, "failed to stop counter %s", counter_name);
+ stop_cyc = rdtsc() - tsc1;
+
+ if (pmc_rw(pmcid, 0, &read_clear_value))
+ err(EX_OSERR, "failed to read and zero %s", counter_name);
+
+ if (pmc_release(pmcid) < 0)
+ err(EX_OSERR, "failed to release %s as a system counter in counting mode",
+ counter_name);
+
+ printf("Counter %s, read value %ld, read/clear value %ld\n",
+ counter_name, read_value, read_clear_value);
+ printf("Cycles to start: %ld\tstop: %ld\tread: %ld\twrite: %ld\n",
+ start_cyc, stop_cyc, read_cyc, stop_cyc);
+
+ return(0);
+}
+
diff --git a/share/examples/indent/indent.pro b/share/examples/indent/indent.pro
new file mode 100644
index 000000000000..c85bfda3f4bc
--- /dev/null
+++ b/share/examples/indent/indent.pro
@@ -0,0 +1,46 @@
+-TFILE
+-Tfd_mask
+-Tfd_set
+-Tlinker_sym_tT
+-Tu_char
+-Tu_int
+-Tu_long
+-Tu_short
+-TTAILQ_HEAD
+-TTAILQ_ENTRY
+-TLIST_HEAD
+-TLIST_ENTRY
+-TSTAILQ_HEAD
+-TSTAILQ_ENTRY
+-TSLIST_HEAD
+-TSLIST_ENTRY
+-bad
+-bap
+-nbbb
+-nbc
+-br
+-nbs
+-c41
+-cd41
+-cdb
+-ce
+-ci4
+-cli0
+-d0
+-di8
+-ndj
+-ei
+-nfc1
+-nfcb
+-i8
+-ip8
+-l79
+-lc77
+-ldi0
+-nlp
+-npcs
+-psl
+-sc
+-nsob
+-ta
+-nv
diff --git a/share/examples/ipfilter/BNF b/share/examples/ipfilter/BNF
new file mode 100644
index 000000000000..ef35d25e9f8a
--- /dev/null
+++ b/share/examples/ipfilter/BNF
@@ -0,0 +1,81 @@
+filter-rule = [ insert ] action in-out [ options ] [ tos ] [ ttl ]
+ [ proto ] [ ip ] [ group ] [ tag ] [ pps ] .
+
+insert = "@" decnumber .
+action = block | "pass" | log | "count" | auth | call .
+in-out = "in" | "out" .
+options = [ log ] [ "quick" ] [ onif [ dup ] [ froute ] ] .
+tos = "tos" decnumber | "tos" hexnumber .
+ttl = "ttl" decnumber .
+proto = "proto" protocol .
+ip = srcdst [ flags ] [ with withopt ] [ icmp ] [ keep ] .
+group = [ "head" decnumber ] [ "group" decnumber ] .
+pps = "pps" decnumber .
+
+onif = "on" interface-name [ "out-via" interface-name ] .
+block = "block" [ return-icmp[return-code] | "return-rst" ] .
+auth = "auth" | "preauth" .
+log = "log" [ "body" ] [ "first" ] [ "or-block" ] [ "level" loglevel ] .
+tag = "tag" tagid .
+call = "call" [ "now" ] function-name "/" decnumber.
+dup = "dup-to" interface-name[":"ipaddr] .
+froute = "fastroute" | "to" interface-name .
+replyto = "reply-to" interface-name [ ":" ipaddr ] .
+protocol = "tcp/udp" | "udp" | "tcp" | "icmp" | decnumber .
+srcdst = "all" | fromto .
+fromto = "from" object "to" object .
+
+return-icmp = "return-icmp" | "return-icmp-as-dest" .
+loglevel = facility"."priority | priority .
+object = addr [ port-comp | port-range ] .
+addr = "any" | nummask | host-name [ "mask" ipaddr | "mask" hexnumber ] .
+port-comp = "port" compare port-num .
+port-range = "port" port-num range port-num .
+flags = "flags" flag { flag } [ "/" flag { flag } ] .
+with = "with" | "and" .
+icmp = "icmp-type" icmp-type [ "code" decnumber ] .
+return-code = "("icmp-code")" .
+keep = "keep" "state" [ "limit" number ] | "keep" "frags" .
+
+nummask = host-name [ "/" decnumber ] .
+host-name = ipaddr | hostname | "any" .
+ipaddr = host-num "." host-num "." host-num "." host-num .
+host-num = digit [ digit [ digit ] ] .
+port-num = service-name | decnumber .
+
+withopt = [ "not" | "no" ] opttype [ [ "," ] withopt ] .
+opttype = "ipopts" | "short" | "nat" | "bad-src" | "lowttl" | "frag" |
+ "mbcast" | "opt" ipopts .
+optname = ipopts [ "," optname ] .
+ipopts = optlist | "sec-class" [ secname ] .
+secname = seclvl [ "," secname ] .
+seclvl = "unclass" | "confid" | "reserv-1" | "reserv-2" | "reserv-3" |
+ "reserv-4" | "secret" | "topsecret" .
+icmp-type = "unreach" | "echo" | "echorep" | "squench" | "redir" |
+ "timex" | "paramprob" | "timest" | "timestrep" | "inforeq" |
+ "inforep" | "maskreq" | "maskrep" | "routerad" |
+ "routersol" | decnumber .
+icmp-code = decumber | "net-unr" | "host-unr" | "proto-unr" | "port-unr" |
+ "needfrag" | "srcfail" | "net-unk" | "host-unk" | "isolate" |
+ "net-prohib" | "host-prohib" | "net-tos" | "host-tos" |
+ "filter-prohib" | "host-preced" | "cutoff-preced" .
+optlist = "nop" | "rr" | "zsu" | "mtup" | "mtur" | "encode" | "ts" | "tr" |
+ "sec" | "lsrr" | "e-sec" | "cipso" | "satid" | "ssrr" | "addext" |
+ "visa" | "imitd" | "eip" | "finn" .
+facility = "kern" | "user" | "mail" | "daemon" | "auth" | "syslog" |
+ "lpr" | "news" | "uucp" | "cron" | "ftp" | "authpriv" |
+ "audit" | "logalert" | "local0" | "local1" | "local2" |
+ "local3" | "local4" | "local5" | "local6" | "local7" .
+priority = "emerg" | "alert" | "crit" | "err" | "warn" | "notice" |
+ "info" | "debug" .
+
+hexnumber = "0" "x" hexstring .
+hexstring = hexdigit [ hexstring ] .
+decnumber = digit [ decnumber ] .
+
+compare = "=" | "!=" | "<" | ">" | "<=" | ">=" | "eq" | "ne" | "lt" | "gt" |
+ "le" | "ge" .
+range = "<>" | "><" .
+hexdigit = digit | "a" | "b" | "c" | "d" | "e" | "f" .
+digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" .
+flag = "F" | "S" | "R" | "P" | "A" | "U" | "C" | "W" .
diff --git a/share/examples/ipfilter/Makefile b/share/examples/ipfilter/Makefile
new file mode 100644
index 000000000000..b1b8b57449f1
--- /dev/null
+++ b/share/examples/ipfilter/Makefile
@@ -0,0 +1,31 @@
+
+PACKAGE=ipf
+FILES= README
+
+# dist sample files
+.PATH: ${.CURDIR}/rules
+FILES+= BASIC.NAT BASIC_1.FW BASIC_2.FW \
+ example.1 example.2 example.3 example.4 example.5 \
+ example.6 example.7 example.8 example.9 example.10 \
+ example.11 example.12 example.13 example.sr firewall \
+ ftp-proxy ftppxy nat-setup nat.eg server tcpstate
+
+# ftp://ftp.OpenBSD.org/pub/OpenBSD/src/share/ipf/ sample files.
+FILES+= example.14 firewall.1 firewall.2 \
+ ipf.conf.permissive ipf.conf.restrictive \
+ ipf.conf.sample ipnat.conf.sample
+
+# http://www.obfuscation.org/ipf/ how-to
+FILES+= ipf-howto.txt
+
+# http://coombs.anu.edu.au/~avalon/ sample files
+FILES+= examples.txt rules.txt
+
+BINMODE=0755
+SCRIPTS= mkfilters
+MAN= mkfilters.1
+
+SCRIPTSDIR= ${SHAREDIR}/examples/ipfilter
+FILESDIR= ${SHAREDIR}/examples/ipfilter
+
+.include <bsd.prog.mk>
diff --git a/share/examples/ipfilter/Makefile.depend b/share/examples/ipfilter/Makefile.depend
new file mode 100644
index 000000000000..11aba52f82cf
--- /dev/null
+++ b/share/examples/ipfilter/Makefile.depend
@@ -0,0 +1,10 @@
+# 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/share/examples/ipfilter/README b/share/examples/ipfilter/README
new file mode 100644
index 000000000000..aa4df9786702
--- /dev/null
+++ b/share/examples/ipfilter/README
@@ -0,0 +1,14 @@
+
+This directory contains various files related to ipfilter.
+
+For information on building ipf based firewalls, read the ipf-howto.txt.
+
+a more up to date version of this file may be found at:
+
+ http://www.obfuscation.org/ipf/
+
+Additional help may be found at the ipf home page:
+
+ http://coombs.anu.edu.au/~avalon/
+
+examples.txt and rules.txt come from this site.
diff --git a/share/examples/ipfilter/example.14 b/share/examples/ipfilter/example.14
new file mode 100644
index 000000000000..c4c1994030ba
--- /dev/null
+++ b/share/examples/ipfilter/example.14
@@ -0,0 +1,61 @@
+#
+# log all inbound packet on le0 which has IP options present
+#
+log in on le0 from any to any with ipopts
+#
+# block any inbound packets on le0 which are fragmented and "too short" to
+# do any meaningful comparison on. This actually only applies to TCP
+# packets which can be missing the flags/ports (depending on which part
+# of the fragment you see).
+#
+block in log quick on le0 from any to any with short frag
+#
+# log all inbound TCP packets with the SYN flag (only) set
+# (NOTE: if it were an inbound TCP packet with the SYN flag set and it
+# had IP options present, this rule and the above would cause it
+# to be logged twice).
+#
+log in on le0 proto tcp from any to any flags S/SA
+#
+# block and log any inbound ICMP unreachables
+#
+block in log on le0 proto icmp from any to any icmp-type unreach
+#
+# block and log any inbound UDP packets on le0 which are going to port 2049
+# (the NFS port).
+#
+block in log on le0 proto udp from any to any port = 2049
+#
+# quickly allow any packets to/from a particular pair of hosts
+#
+pass in quick from any to 10.1.3.2/32
+pass in quick from any to 10.1.0.13/32
+pass in quick from 10.1.3.2/32 to any
+pass in quick from 10.1.0.13/32 to any
+#
+# block (and stop matching) any packet with IP options present.
+#
+block in quick on le0 from any to any with ipopts
+#
+# allow any packet through
+#
+pass in from any to any
+#
+# block any inbound UDP packets destined for these subnets.
+#
+block in on le0 proto udp from any to 10.1.3.0/24
+block in on le0 proto udp from any to 10.1.1.0/24
+block in on le0 proto udp from any to 10.1.2.0/24
+#
+# block any inbound TCP packets with only the SYN flag set that are
+# destined for these subnets.
+#
+block in on le0 proto tcp from any to 10.1.3.0/24 flags S/SA
+block in on le0 proto tcp from any to 10.1.2.0/24 flags S/SA
+block in on le0 proto tcp from any to 10.1.1.0/24 flags S/SA
+#
+# block any inbound ICMP packets destined for these subnets.
+#
+block in on le0 proto icmp from any to 10.1.3.0/24
+block in on le0 proto icmp from any to 10.1.1.0/24
+block in on le0 proto icmp from any to 10.1.2.0/24
diff --git a/share/examples/ipfilter/examples.txt b/share/examples/ipfilter/examples.txt
new file mode 100644
index 000000000000..2faf50a16a0b
--- /dev/null
+++ b/share/examples/ipfilter/examples.txt
@@ -0,0 +1,514 @@
+IP Filter Examples
+
+ [Image] Permissions
+ [Image] Interface
+ [Image] Netmasks and hosts
+ [Image] IP Protocols
+ [Image] IP Options
+ [Image] IP Fragments
+ [Image] TCP/UDP Ports
+ [Image] ICMP type/code
+ [Image] TCP Flags (established)
+ [Image] Responding to a BAD packet
+ [Image] IP Security Classes
+ [Image] Packet state filtering
+ [Image] Network Address Translation (NAT)
+ [Image] Transparent Proxy Support
+ [Image] Transparent routing
+ [Image] Logging packets to network devices
+ [Image] Rule groups
+ Authenticating packets
+ Pre-authenticating packets
+
+ ------------------------------------------------------------------------
+
+Permission Specifying.
+
+To specify where to pass through or to block a packet, either block or pass
+is used. In and out are used to describe the direction in which the packet
+is travelling through a network interface. Eg:
+
+# setup default to block all packets.
+block in all
+block out all
+# pass packets from host firewall to any destination
+pass in from firewall to any
+
+ ------------------------------------------------------------------------
+
+Select network Interfaces
+
+To select which interface a packet is currently associated with, either its
+destination as a result of route processing or where it has been received
+from, the on keyword is used. Whilst not compulsory, it is recommended that
+each rule include it for clarity. Eg:
+
+# drop all inbound packets from localhost coming from ethernet
+block in on le0 from localhost to any
+
+ ------------------------------------------------------------------------
+
+Netmasks and hosts
+
+As not all networks are formed with classical network boundaries, it is
+necessary to provide a mechanism to support VLSM (Variable Length Subnet
+Masks). This package provides several ways to do this. Eg:
+
+#
+block in on le0 from mynet/26 to any
+#
+block in on le0 from mynet/255.255.255.192 to any
+#
+block in on le0 from mynet mask 255.255.255.192 to any
+#
+block in on le0 from mynet mask 0xffffffc0 to any
+
+Are all valid and legal syntax with this package. However, when regenerating
+rules (ie using ipfstat), this package will prefer to use the shortest valid
+notation (top down).
+
+The default netmask, when none is given is 255.255.255.255 or "/32".
+
+To invert the match on a hostname or network, include an ! before the name
+or number with no space between them.
+ ------------------------------------------------------------------------
+
+Protocol
+
+To filter on an individual protocol, it is possible to specify the protocol
+in a filter rule. Eg:
+
+# block all incoming ICMP packets
+block in on le0 proto icmp all
+
+The name of the protocol can be any valid name from /etc/protocols or a
+number.
+
+# allow all IP packets in which are protocol 4
+pass in on le0 proto 4 all
+
+There is one exception to this rule, being "tcp/udp". If given in a ruleset,
+it will match either of the two protocols. This is useful when setting up
+port restrictions. Eg:
+
+# prevent any packets destined for NFS from coming in
+block in on le0 proto tcp/udp from any to any port = 2049
+
+ ------------------------------------------------------------------------
+
+Filtering IP fragments
+
+IP fragments are bad news, in general. Recent study has shown that IP
+fragments can pose a large threat to IP packet filtering, IF there are rules
+used which rely on data which may be distributed across fragments. To this
+package, the threat is that the TCP flags field of the TCP packet may be in
+the 2nd or 3rd fragment or possibly be believed to be in the first when
+actually in the 2nd or 3rd.
+
+To filter out these nasties, it is possible to select fragmented packets out
+as follows:
+
+#
+# get rid of all IP fragments
+#
+block in all with frag
+
+The problem arises that fragments can actually be a non-malicious. The
+really malicious ones can be grouped under the term "short fragments" and
+can be filtered out as follows:
+
+#
+# get rid of all short IP fragments (too small for valid comparison)
+#
+block in proto tcp all with short
+
+ ------------------------------------------------------------------------
+
+IP Options
+
+IP options have a bad name for being a general security threat. They can be
+of some use, however, to programs such as traceroute but many find this
+usefulness not worth the risk.
+
+Filtering on IP options can be achieved two ways. The first is by naming
+them collectively and is done as follows:
+
+#
+# drop and log any IP packets with options set in them.
+#
+block in log all with ipopts
+#
+
+The second way is to actually list the names of the options you wish to
+filter.
+
+#
+# drop any source routing options
+#
+block in quick all with opt lsrr
+block in quick all with opt ssrr
+
+[Image] NOTE that options are matched explicitly, so if I had lsrr,ssrr it
+would only match packets with both options set.
+
+It is also possible to select packets which DON'T have various options
+present in the packet header. For example, to allow telnet connections
+without any IP options present, the following would be done:
+
+#
+# Allow anyone to telnet in so long as they don't use IP options.
+#
+pass in proto tcp from any to any port = 23 with no ipopts
+#
+# Allow packets with strict source routing and no loose source routing
+#
+pass in from any to any with opt ssrr not opt lsrr
+
+ ------------------------------------------------------------------------
+
+Filtering by ports
+
+Filtering by port number only works with the TCP and UDP IP protocols. When
+specifying port numbers, either the number or the service name from
+/etc/services may be used. If the proto field is used in a filter rule, it
+will be used in conjunction with the port name in determining the port
+number.
+
+The possible operands available for use with port numbers are:
+
+Operand Alias Parameters Result
+< lt port# true if port is less than given value
+> gt port# true if port is greater than given value
+= eq port# true if port is equal to than given value
+!= ne port# true if port is not equal to than given value
+<= le port# true if port is less than or equal to given value
+=> ge port# true if port is greater than or equal to given value
+
+Eg:
+
+#
+# allow any TCP packets from the same subnet as foo is on through to host
+# 10.1.1.2 if they are destined for port 6667.
+#
+pass in proto tcp from fubar/24 to 10.1.1.2/32 port = 6667
+#
+# allow in UDP packets which are NOT from port 53 and are destined for
+# localhost
+#
+pass in proto udp from fubar port != 53 to localhost
+
+Two range comparisons are also possible:
+
+Expression Syntax:
+port1# <> port2# true if port is less than port1 or greater than port2
+port1# >< port2# true if port is greater than port1 and less than port2
+
+[Image] NOTE that in neither case, when the port number is equal to one of
+those given, does it match. Eg:
+
+#
+# block anything trying to get to X terminal ports, X:0 to X:9
+#
+block in proto tcp from any to any port 5999 >< 6010
+#
+# allow any connections to be made, except to BSD print/r-services
+# this will also protect syslog.
+#
+block in proto tcp/udp all
+pass in proto tcp/udp from any to any port 512 <> 515
+
+Note that the last one above could just as easily be done in the reverse
+fashion: allowing everything through and blocking only a small range. Note
+that the port numbers are different, however, due to the difference in the
+way they are compared.
+
+#
+# allow any connections to be made, except to BSD print/r-services
+# this will also protect syslog.
+#
+pass in proto tcp/udp all
+block in proto tcp/udp from any to any port 511 >< 516
+
+ ------------------------------------------------------------------------
+
+TCP Flags (established)
+
+Filtering on TCP flags is useful, but fraught with danger. I'd recommend
+that before using TCP flags in your IP filtering, you become at least a
+little bit acquainted with what the role of each of them is and when they're
+used. This package will compare the flags present in each TCP packet, if
+asked, and match if those present in the TCP packet are the same as in the
+IP filter rule.
+
+Some IP filtering/firewall packages allow you to filter out TCP packets
+which belong to an "established" connection. This is, simply put, filtering
+on packets which have the ACK bit set. The ACK bit is only set in packets
+transmitted during the lifecycle of a TCP connection. It is necessary for
+this flag to be present from either end for data to be transferred. If you
+were using a rule which as worded something like:
+
+allow proto tcp 10.1.0.0 255.255.0.0 port = 23 10.2.0.0 255.255.0.0 established
+
+It could be rewritten as:
+
+pass in proto tcp 10.1.0.0/16 port = 23 10.2.0.0/16 flags A/A
+pass out proto tcp 10.1.0.0/16 port = 23 10.2.0.0/16 flags A/A
+
+A more useful flag to filter on, for TCP connections, I find, is the SYN
+flag. This is only set during the initial stages of connection negotiation,
+and for the very first packet of a new TCP connection, it is the only flag
+set. At all other times, an ACK or maybe even an URG/PUSH flag may be set.
+So, if I want to stop connections being made to my internal network
+(10.1.0.0) from the outside network, I might do something like:
+
+#
+# block incoming connection requests to my internal network from the big bad
+# internet.
+#
+block in on le0 proto tcp from any to 10.1.0.0/16 flags S/SA
+
+If you wanted to block the replies to this (the SYN-ACK's), then you might
+do:
+
+block out on le0 proto tcp from 10.1.0.0 to any flags SA/SA
+
+where SA represents the SYN-ACK flags both being set.
+
+The flags after the / represent the TCP flag mask, indicating which bits of
+the TCP flags you are interested in checking. When using the SYN bit in a
+check, you SHOULD specify a mask to ensure that your filter CANNOT be
+defeated by a packet with SYN and URG flags, for example, set (to Unix, this
+is the same as a plain SYN).
+ ------------------------------------------------------------------------
+
+ICMP Type/Code
+
+ICMP can be a source of a lot of trouble for Internet Connected networks.
+Blocking out all ICMP packets can be useful, but it will disable some
+otherwise useful programs, such as "ping". Filtering on ICMP type allows for
+pings (for example) to work. Eg:
+
+# block all ICMP packets.
+#
+block in proto icmp all
+#
+# allow in ICMP echos and echo-replies.
+#
+pass in on le1 proto icmp from any to any icmp-type echo
+pass in on le1 proto icmp from any to any icmp-type echorep
+
+To specify an ICMP code, the numeric value must be used. So, if we wanted to
+block all port-unreachables, we would do:
+
+#
+# block all ICMP destination unreachable packets which are port-unreachables
+#
+block in on le1 proto icmp from any to any icmp-type unreach code 3
+
+ ------------------------------------------------------------------------
+
+Responding to a BAD packet
+
+To provide feedback to people trying to send packets through your filter
+which you wish to disallow, you can send back either an ICMP error
+(Destination Unreachable) or, if they're sending a TCP packet, a TCP RST
+(Reset).
+
+What's the difference ? TCP/IP stacks take longer to pass the ICMP errors
+back, through to the application, as they can often be due to temporary
+problems (network was unplugged for a second) and it is `incorrect' to shut
+down a connection for this reason. Others go to the other extreme and will
+shut down all connections between the two hosts for which the ICMP error is
+received. The TCP RST, however, is for only *one* connection (cannot be used
+for more than one) and will cause the connection to immediately shut down.
+So, for example, if you're blocking port 113, and setup a rule to return a
+TCP RST rather than nothing or an ICMP packet, you won't experience any
+delay if the other end was attempting to make a connection to an identd
+service.
+
+Some examples are as follows:
+
+#
+# block all incoming TCP connections but send back a TCP-RST for ones to
+# the ident port
+#
+block in proto tcp from any to any flags S/SA
+block return-rst in quick proto tcp from any to any port = 113 flags S/SA
+#
+# block all inbound UDP packets and send back an ICMP error.
+#
+block return-icmp in proto udp from any to any
+
+When returning ICMP packets, it is also possible to specify the type of ICMP
+error return. This was requested so that traceroute traces could be forced
+to end elegantly. To do this, the requested ICMP Unreachable code is placed
+in brackets following the "return-icmp" directive:
+
+#
+# block all inbound UDP packets and send back an ICMP error.
+#
+block return-icmp (3) in proto udp from any to any port > 30000
+block return-icmp (port-unr) in proto udp from any to any port > 30000
+
+Those two examples are equivalent, and return an ICMP port unreachable error
+packet to in response to any UDP packet received destined for a port greater
+than 30,000.
+ ------------------------------------------------------------------------
+
+Filtering IP Security Classes
+
+For users who have packets which contain IP security bits, filtering on the
+defined classes and authority levels is supported. Currently, filtering on
+16bit authority flags is not supported.
+
+As with ipopts and other IP options, it is possible to say that the packet
+only matches if a certain class isn't present.
+
+Some examples of filtering on IP security options:
+
+#
+# drop all packets without IP security options
+#
+block in all with no opt sec
+#
+# only allow packets in and out on le0 which are top secret
+#
+block out on le1 all
+pass out on le1 all with opt sec-class topsecret
+block in on le1 all
+pass in on le1 all with opt sec-class topsecret
+
+ ------------------------------------------------------------------------
+
+Packet state filtering
+
+Packet state filtering can be used for any TCP flow to short-cut later
+filtering. The "short-cuts" are kept in a table, with no alterations to the
+packet filter list made. Subsequent packets, if a matching packet is found
+in the table, are not passed through the list. For TCP flows, the filter
+will follow the ack/sequence numbers of packets and only allow packets
+through which fall inside the correct window.
+
+#
+# Keep state for all outgoing telnet connections
+# and disallow all other TCP traffic.
+#
+pass out on le1 proto tcp from any to any port = telnet keep state
+block out on le1 all
+
+For UDP packets, packet exchanges are effectively stateless. However, if a
+packet is first sent out from a given port, a reply is usually expected in
+answer, in the `reverse' direction.
+
+#
+# allow UDP replies back from name servers
+#
+pass out on le1 proto udp from any to any port = domain keep state
+
+Held UDP state is timed out, as is TCP state for entries added which do not
+have the SYN flag set. If an entry is created with the SYN flag set, any
+subsequent matching packet which doesn't have this flag set (ie a SYN-ACK)
+will cause it to be "timeless" (actually, the timeout defaults to 5 days),
+until either a FIN or RST is seen.
+
+ ------------------------------------------------------------------------
+
+Network Address Translation (NAT)
+
+Network address translation is used to remap IP #'s from one address range
+to another range of network addresses. For TCP and UDP, this also can
+include the port numbers. The IP#'s/port #'s are changed when a packet is
+going out through an interface and IP Filter matches it against a NAT rules.
+
+Packets coming back in the same interface are remapped, as a matter of
+course, to their original address information.
+
+# map all tcp connections from 10.1.0.0/16 to 240.1.0.1, changing the source
+# port number to something between 10,000 and 20,000 inclusive. For all other
+# IP packets, allocate an IP # between 240.1.0.0 and 240.1.0.255, temporarily
+# for each new user. In this example, ed1 is the external interface.
+# Use ipnat, not ipf to load these rules.
+#
+map ed1 10.1.0.0/16 -> 240.1.0.1/32 portmap tcp 10000:20000
+map ed1 10.1.0.0/16 -> 240.1.0.0/24
+
+ ------------------------------------------------------------------------
+
+Transparent Proxy Suppoer
+
+Transparent proxies are supported through redirection, which works in a
+similar way to NAT, except that rules are triggered by input packets. To
+effect redirection rules, ipnat must be used (same as for NAT) rather than
+ipf.
+
+# Redirection is triggered for input packets.
+# For example, to redirect FTP connections through this box (in this case ed0
+# is the interface on the "inside" where default routes point), to the local
+# ftp port, forcing them to connect through a proxy, you would use:
+#
+rdr ed0 0.0.0.0/0 port ftp -> 127.0.0.1 port ftp
+
+ ------------------------------------------------------------------------
+
+Transparent routing
+
+Transparent routing can be performed in two ways using IP Filter. The first
+is to use the keyword "fastroute" in a rule, using the normal route lookup
+to occur or using a fixed route with "to". Both effect transparent routing
+by not causing any decrement in the TTL to occur as it passes through the
+kernel.
+
+# Route all UDP packets through transparently.
+#
+pass in quick fastroute proto udp all
+#
+# Route all ICMP packets to network 10 (on le0) out through le1, to "router"
+#
+pass in quick on le0 to le1:router proto icmp all
+
+ ------------------------------------------------------------------------
+
+Logging packets to the network
+
+Logging packets to the network devices is supported for both packets being
+passed through the filter and those being blocked. For packets being passed
+on, the "dup-to" keyword must be used, but for packets being blocked, either
+"to" (more efficient) or "dup-to" can be used.
+
+To log packets to the interface without requiring ARP to work, create a
+static arp cache for a meaningless IP# (say 10.0.0.1) and log packets to
+this IP#.
+
+# Log all short TCP packets to qe3, with "packetlog" as the intended
+# destination for the packet.
+#
+block in quick to qe3:packetlog proto tcp all with short
+#
+# Log all connection attempts for TCP
+#
+pass in quick on ppp0 dup-to le1:packetlog proto tcp all flags S/SA
+
+ ------------------------------------------------------------------------
+
+Rule groups
+
+To aide in making rule processing more efficient, it is possible to setup
+rule `groups'. By default, all rules are in group 0 and all other groups
+have it as their ultimate parent. To start a new group, a rule includes a
+`head' statement, such as this:
+
+# Process all incoming ppp packets on ppp0 with group 100, with the default for
+# this interface to block all incoming.
+#
+block in quick on ppp0 all head 100
+
+If we then wanted to allow people to connect to our WWW server, via ppp0, we
+could then just add a rule about WWW. NOTE: only packets which match the
+above rule are processed by any group 100 rules.
+
+# Allow connections to the WWW server via ppp0.
+#
+pass in quick proto tcp from any to any port = WWW keep state group 100
+
+ ------------------------------------------------------------------------
+Return to the IP Filter home page
diff --git a/share/examples/ipfilter/firewall.1 b/share/examples/ipfilter/firewall.1
new file mode 100644
index 000000000000..077a4607b192
--- /dev/null
+++ b/share/examples/ipfilter/firewall.1
@@ -0,0 +1,35 @@
+#
+# This is an example of a very light firewall used to guard against
+# some of the most easily exploited common security holes.
+#
+# The example assumes it is running on a gateway with interface ppp0
+# attached to the outside world, and interface ed0 attached to
+# network 192.168.4.0 which needs to be protected.
+#
+#
+# Pass any packets not explicitly mentioned by subsequent rules
+#
+pass out from any to any
+pass in from any to any
+#
+# Block any inherently bad packets coming in from the outside world.
+# These include ICMP redirect packets and IP fragments so short the
+# filtering rules won't be able to examine the whole UDP/TCP header.
+#
+block in log quick on ppp0 proto icmp from any to any icmp-type redir
+block in log quick on ppp0 proto tcp/udp all with short
+#
+# Block any IP spoofing attempts. (Packets "from" our network
+# shouldn't be coming in from outside).
+#
+block in log quick on ppp0 from 192.168.4.0/24 to any
+block in log quick on ppp0 from localhost to any
+block in log quick on ppp0 from 0.0.0.0/32 to any
+block in log quick on ppp0 from 255.255.255.255/32 to any
+#
+# Block any incoming traffic to NFS ports, to the RPC portmapper, and
+# to X servers.
+#
+block in log on ppp0 proto tcp/udp from any to any port = sunrpc
+block in log on ppp0 proto tcp/udp from any to any port = 2049
+block in log on ppp0 proto tcp from any to any port = 6000
diff --git a/share/examples/ipfilter/firewall.2 b/share/examples/ipfilter/firewall.2
new file mode 100644
index 000000000000..d87721088afc
--- /dev/null
+++ b/share/examples/ipfilter/firewall.2
@@ -0,0 +1,69 @@
+#
+# This is an example of a fairly heavy firewall used to keep everyone
+# out of a particular network while still allowing people within that
+# network to get outside.
+#
+# The example assumes it is running on a gateway with interface ppp0
+# attached to the outside world, and interface ed0 attached to
+# network 192.168.4.0 which needs to be protected.
+#
+#
+# Pass any packets not explicitly mentioned by subsequent rules
+#
+pass out from any to any
+pass in from any to any
+#
+# Block any inherently bad packets coming in from the outside world.
+# These include ICMP redirect packets, IP fragments so short the
+# filtering rules won't be able to examine the whole UDP/TCP header,
+# and anything with IP options.
+#
+block in log quick on ppp0 proto icmp from any to any icmp-type redir
+block in log quick on ppp0 proto tcp/udp all with short
+block in log quick on ppp0 from any to any with ipopts
+#
+# Block any IP spoofing attempts. (Packets "from" our network
+# shouldn't be coming in from outside).
+#
+block in log quick on ppp0 from 192.168.4.0/24 to any
+block in log quick on ppp0 from localhost to any
+block in log quick on ppp0 from 0.0.0.0/32 to any
+block in log quick on ppp0 from 255.255.255.255/32 to any
+#
+# Block all incoming UDP traffic except talk and DNS traffic. NFS
+# and portmap are special-cased and logged.
+#
+block in on ppp0 proto udp from any to any
+block in log on ppp0 proto udp from any to any port = sunrpc
+block in log on ppp0 proto udp from any to any port = 2049
+pass in on ppp0 proto udp from any to any port = domain
+pass in on ppp0 proto udp from any to any port = talk
+pass in on ppp0 proto udp from any to any port = ntalk
+#
+# Block all incoming TCP traffic connections to known services,
+# returning a connection reset so things like ident don't take
+# forever timing out. Don't log ident (auth port) as it's so common.
+#
+block return-rst in log on ppp0 proto tcp from any to any flags S/SA
+block return-rst in on ppp0 proto tcp from any to any port = auth flags S/SA
+#
+# Allow incoming TCP connections to ports between 1024 and 5000, as
+# these don't have daemons listening but are used by outgoing
+# services like ftp and talk. For slightly more obscurity (though
+# not much more security), the second commented out rule can chosen
+# instead.
+#
+pass in on ppp0 proto tcp from any to any port 1024 >< 5000
+#pass in on ppp0 proto tcp from any port = ftp-data to any port 1024 >< 5000
+#
+# Now allow various incoming TCP connections to particular hosts, TCP
+# to the main nameserver so secondaries can do zone transfers, SMTP
+# to the mail host, www to the web server (which really should be
+# outside the firewall if you care about security), and ssh to a
+# hypothetical machine caled 'gatekeeper' that can be used to gain
+# access to the protected network from the outside world.
+#
+pass in on ppp0 proto tcp from any to ns1 port = domain
+pass in on ppp0 proto tcp from any to mail port = smtp
+pass in on ppp0 proto tcp from any to www port = www
+pass in on ppp0 proto tcp from any to gatekeeper port = ssh
diff --git a/share/examples/ipfilter/ipf-howto.txt b/share/examples/ipfilter/ipf-howto.txt
new file mode 100644
index 000000000000..66f67bd96bf1
--- /dev/null
+++ b/share/examples/ipfilter/ipf-howto.txt
@@ -0,0 +1,3167 @@
+
+
+
+
+
+
+ IP Filter Based Firewalls HOWTO
+
+ Brendan Conoboy <synk@swcp.com>
+ Erik Fichtner <emf@obfuscation.org>
+
+ Fri Apr 20 09:31:14 EDT 2001
+
+
+
+
+
+
+ Abstract: This document is intended to introduce a new
+ user to the IP Filter firewalling package and, at the
+ same time, teach the user some basic fundamentals of
+ good firewall design.
+
+
+
+
+
+
+
+
+
+
+
+
+1. Introduction
+
+ IP Filter is a great little firewall package. It does
+just about everything other free firewalls (ipfwadm,
+ipchains, ipfw) do, but it's also portable and does neat
+stuff the others don't. This document is intended to make
+some cohesive sense of the sparse documentation presently
+available for ipfilter. Some prior familiarity with packet
+filtering will be useful, however too much familiarity may
+make this document a waste of your time. For greater under-
+standing of firewalls, the authors recommend reading Build-
+ing Internet Firewalls, Chapman & Zwicky, O'Reilly and Asso-
+ciates; and TCP/IP Illustrated, Volume 1, Stevens, Addison-
+Wesley.
+
+
+
+
+
+1.1. Disclaimer
+
+ The authors of this document are not responsible for
+any damages incurred due to actions taken based on this doc-
+ument. This document is meant as an introduction to building
+a firewall based on IP-Filter. If you do not feel
+
+
+
+
+
+
+
+
+
+ -2-
+
+
+comfortable taking responsibility for your own actions, you
+should stop reading this document and hire a qualified secu-
+rity professional to install your firewall for you.
+
+
+1.2. Copyright
+
+ Unless otherwise stated, HOWTO documents are copy-
+righted by their respective authors. HOWTO documents may be
+reproduced and distributed in whole or in part, in any
+medium physical or electronic, as long as this copyright
+notice is retained on all copies. Commercial redistribution
+is allowed and encouraged; however, the authors would like
+to be notified of any such distributions.
+
+ All translations, derivative works, or aggregate works
+incorporating any HOWTO documents must be covered under this
+copyright notice. That is, you may not produce a derivative
+work from a HOWTO and impose additional restrictions on its
+distribution. Exceptions to these rules may be granted under
+certain conditions; please contact the HOWTO coordinator.
+
+ In short, we wish to promote dissemination of this
+information through as many channels as possible. However,
+we do wish to retain copyright on the HOWTO documents, and
+would like to be notified of any plans to redistribute the
+HOWTOs.
+
+
+1.3. Where to obtain the important pieces
+
+ The official IPF homepage is at:
+<http://coombs.anu.edu.au/~avalon/ip-filter.html>
+
+ The most up-to-date version of this document can be
+found at: <http://www.obfuscation.org/ipf/>
+
+
+
+
+2. Basic Firewalling
+
+ This section is designed to familiarize you with ipfil-
+ter's syntax, and firewall theory in general. The features
+discussed here are features you'll find in any good firewall
+package. This section will give you a good foundation to
+make reading and understanding the advanced section very
+easy. It must be emphasized that this section alone is not
+enough to build a good firewall, and that the advanced sec-
+tion really is required reading for anybody who wants to
+build an effective security system.
+
+
+
+
+
+
+
+
+
+
+
+
+ -3-
+
+
+2.1. Config File Dynamics, Order and Precedence
+
+ IPF (IP Filter) has a config file (as opposed to say,
+running some command again and again for each new rule).
+The config file drips with Unix: There's one rule per line,
+the "#" mark denotes a comment, and you can have a rule and
+a comment on the same line. Extraneous whitespace is
+allowed, and is encouraged to keep the rules readable.
+
+
+2.2. Basic Rule Processing
+
+ The rules are processed from top to bottom, each one
+appended after another. This quite simply means that if the
+entirety of your config file is:
+
+ block in all
+ pass in all
+
+The computer sees it as:
+
+ block in all
+ pass in all
+
+Which is to say that when a packet comes in, the first thing
+IPF applies is:
+
+ block in all
+
+Should IPF deem it necessary to move on to the next rule, it
+would then apply the second rule:
+
+ pass in all
+
+ At this point, you might want to ask yourself "would
+IPF move on to the second rule?" If you're familiar with
+ipfwadm or ipfw, you probably won't ask yourself this.
+Shortly after, you will become bewildered at the weird way
+packets are always getting denied or passed when they
+shouldn't. Many packet filters stop comparing packets to
+rulesets the moment the first match is made; IPF is not one
+of them.
+
+ Unlike the other packet filters, IPF keeps a flag on
+whether or not it's going to pass the packet. Unless you
+interrupt the flow, IPF will go through the entire ruleset,
+making its decision on whether or not to pass or drop the
+packet based on the last matching rule. The scene: IP Fil-
+ter's on duty. It's been been scheduled a slice of CPU
+time. It has a checkpoint clipboard that reads:
+
+ block in all
+ pass in all
+
+
+
+
+
+
+
+
+
+
+ -4-
+
+
+A packet comes in the interface and it's time to go to work.
+It takes a look at the packet, it takes a look at the first
+rule:
+
+ block in all
+
+"So far I think I will block this packet" says IPF. It
+takes a look at the second rule:
+
+ pass in all
+
+"So far I think I will pass this packet" says IPF. It takes
+a look at a third rule. There is no third rule, so it goes
+with what its last motivation was, to pass the packet
+onward.
+
+It's a good time to point out that even if the ruleset had
+been
+
+ block in all
+ block in all
+ block in all
+ block in all
+ pass in all
+
+that the packet would still have gone through. There is no
+cumulative effect. The last matching rule always takes
+precedence.
+
+2.3. Controlling Rule Processing
+
+ If you have experience with other packet filters, you
+may find this layout to be confusing, and you may be specu-
+lating that there are problems with portability with other
+filters and speed of rule matching. Imagine if you had 100
+rules and most of the applicable ones were the first 10.
+There would be a terrible overhead for every packet coming
+in to go through 100 rules every time. Fortunately, there
+is a simple keyword you can add to any rule that makes it
+take action at that match. That keyword is quick.
+
+Here's a modified copy of the original ruleset using the
+quick keyword:
+
+ block in quick all
+ pass in all
+
+In this case, IPF looks at the first rule:
+
+ block in quick all
+
+The packet matches and the search is over. The packet is
+expunged without a peep. There are no notices, no logs, no
+memorial service. Cake will not be served. So what about
+
+
+
+
+
+
+
+
+
+ -5-
+
+
+the next rule?
+
+ pass in all
+
+ This rule is never encountered. It could just as eas-
+ily not be in the config file at all. The sweeping match of
+all and the terminal keyword quick from the previous rule
+make certain that no rules are followed afterward.
+
+ Having half a config file laid to waste is rarely a
+desirable state. On the other hand, IPF is here to block
+packets and as configured, it's doing a very good job.
+Nonetheless, IPF is also here to let some packets through,
+so a change to the ruleset to make this possible is called
+for.
+
+2.4. Basic filtering by IP address
+
+ IPF will match packets on many criteria. The one that
+we most commonly think of is the IP address. There are some
+blocks of address space from which we should never get traf-
+fic. One such block is from the unroutable networks,
+192.168.0.0/16 (/16 is the CIDR notation for a netmask. You
+may be more familiar with the dotted decimal format,
+255.255.0.0. IPF accepts both). If you wanted to block
+192.168.0.0/16, this is one way to do it:
+
+ block in quick from 192.168.0.0/16 to any
+ pass in all
+
+Now we have a less stringent ruleset that actually does
+something for us. Let's imagine a packet comes in from
+1.2.3.4. The first rule is applied:
+
+ block in quick from 192.168.0.0/16 to any
+
+The packet is from 1.2.3.4, not 192.168.*.*, so there is no
+match. The second rule is applied:
+
+ pass in all
+
+The packet from 1.2.3.4 is definitely a part of all, so the
+packet is sent to whatever it's destination happened to be.
+
+ On the other hand, suppose we have a packet that comes
+in from 192.168.1.2. The first rule is applied:
+
+ block in quick from 192.168.0.0/16 to any
+
+There's a match, the packet is dropped, and that's the end.
+Again, it doesn't move to the second rule because the first
+rule matches and contains the quick keyword.
+
+
+
+
+
+
+
+
+
+
+
+ -6-
+
+
+ At this point you can build a fairly extensive set of
+definitive addresses which are passed or blocked. Since
+we've already started blocking private address space from
+entering our firewall, let's take care of the rest of it:
+
+ block in quick from 192.168.0.0/16 to any
+ block in quick from 172.16.0.0/12 to any
+ block in quick from 10.0.0.0/8 to any
+ pass in all
+
+The first three address blocks are some of the private IP
+space.
+
+2.5. Controlling Your Interfaces
+
+ It seems very frequent that companies have internal
+networks before they want a link to the outside world. In
+fact, it's probably reasonable to say that's the main reason
+people consider firewalls in the first place. The machine
+that bridges the outside world to the inside world and vice
+versa is the router. What separates the router from any
+other machine is simple: It has more than one interface.
+
+ Every packet you receive comes from a network inter-
+face; every packet you transmit goes out a network inter-
+face. Say your machine has 3 interfaces, lo0 (loopback),
+xl0 (3com ethernet), and tun0 (FreeBSD's generic tunnel
+interface that PPP uses), but you don't want packets coming
+in on the tun0 interface?
+
+ block in quick on tun0 all
+ pass in all
+
+In this case, the on keyword means that the data is coming
+in on the named interface. If a packet comes in on tun0,
+the first rule will block it. If a packet comes in on lo0
+or in on xl0, the first rule will not match, the second rule
+will, the packet will be passed.
+
+2.6. Using IP Address and Interface Together
+
+ It's an odd state of affairs when one decides it best
+to have the tun0 interface up, but not allow any data to be
+received from it. The more criteria the firewall matches
+against, the tighter (or looser) the firewall can become.
+Maybe you want data from tun0, but not from 192.168.0.0/16?
+This is the start of a powerful firewall.
+
+ block in quick on tun0 from 192.168.0.0/16 to any
+-----------
+ See rfc1918 at
+<http://www.faqs.org/rfcs/rfc1918.html> and
+<http://www.ietf.org/internet-drafts/draft-man-
+ning-dsua-06.txt>
+
+
+
+
+
+
+
+
+
+ -7-
+
+
+ pass in all
+
+Compare this to our previous rule:
+
+ block in quick from 192.168.0.0/16 to any
+ pass in all
+
+The old way, all traffic from 192.168.0.0/16, regardless of
+interface, was completely blocked. The new way, using on
+tun0 means that it's only blocked if it comes in on the tun0
+interface. If a packet arrived on the xl0 interface from
+192.168.0.0/16, it would be passed.
+
+ At this point you can build a fairly extensive set of
+definitive addresses which are passed or blocked. Since
+we've already started blocking private address space from
+entering tun0, let's take care of the rest of it:
+
+ block in quick on tun0 from 192.168.0.0/16 to any
+ block in quick on tun0 from 172.16.0.0/12 to any
+ block in quick on tun0 from 10.0.0.0/8 to any
+ block in quick on tun0 from 127.0.0.0/8 to any
+ block in quick on tun0 from 0.0.0.0/8 to any
+ block in quick on tun0 from 169.254.0.0/16 to any
+ block in quick on tun0 from 192.0.2.0/24 to any
+ block in quick on tun0 from 204.152.64.0/23 to any
+ block in quick on tun0 from 224.0.0.0/3 to any
+ pass in all
+
+You've already seen the first three blocks, but not the
+rest. The fourth is a largely wasted class-A network used
+for loopback. Much software communicates with itself on
+127.0.0.1 so blocking it from an external source is a good
+idea. The fifth, 0.0.0.0/8, should never be seen on the
+internet. Most IP stacks treat "0.0.0.0/32" as the default
+gateway, and the rest of the 0.*.*.* network gets handled
+strangely by various systems as a byproduct of how routing
+decisions are made. You should treat 0.0.0.0/8 just like
+127.0.0.0/8. 169.254.0.0/16 has been assigned by the IANA
+for use in auto-configuration when systems have not yet been
+able to obtain an IP address via DHCP or the like. Most
+notably, Microsoft Windows will use addresses in this range
+if they are set to DHCP and cannot find a DHCP server.
+192.0.2.0/24 has also been reserved for use as an example IP
+netblock for documentation authors. We specifically do not
+use this range as it would cause confusion when we tell you
+to block it, and thus all our examples come from
+20.20.20.0/24. 204.152.64.0/23 is an odd netblock reserved
+by Sun Microsystems for private cluster interconnects, and
+blocking this is up to your own judgement. Lastly,
+224.0.0.0/3 wipes out the "Class D and E" networks which is
+used mostly for multicast traffic, although further defini-
+tion of "Class E" space can be found in RFC 1166.
+
+
+
+
+
+
+
+
+
+
+ -8-
+
+
+ There's a very important principle in packet filtering
+which has only been alluded to with the private network
+blocking and that is this: When you know there's certain
+types of data that only comes from certain places, you setup
+the system to only allow that kind of data from those
+places. In the case of the unroutable addresses, you know
+that nothing from 10.0.0.0/8 should be arriving on tun0
+because you have no way to reply to it. It's an illegiti-
+mate packet. The same goes for the other unroutables as
+well as 127.0.0.0/8.
+
+ Many pieces of software do all their authentication
+based upon the packet's originating IP address. When you
+have an internal network, say 20.20.20.0/24, you know that
+the only traffic for that internal network is going to come
+off the local ethernet. Should a packet from 20.20.20.0/24
+arrive over a PPP dialup, it's perfectly reasonable to drop
+it on the floor, or put it in a dark room for interrogation.
+It should by no means be allowed to get to its final desti-
+nation. You can accomplish this particularly easily with
+what you already know of IPF. The new ruleset would be:
+
+ block in quick on tun0 from 192.168.0.0/16 to any
+ block in quick on tun0 from 172.16.0.0/12 to any
+ block in quick on tun0 from 10.0.0.0/8 to any
+ block in quick on tun0 from 127.0.0.0/8 to any
+ block in quick on tun0 from 0.0.0.0/8 to any
+ block in quick on tun0 from 169.254.0.0/16 to any
+ block in quick on tun0 from 192.0.2.0/24 to any
+ block in quick on tun0 from 204.152.64.0/23 to any
+ block in quick on tun0 from 224.0.0.0/3 to any
+ block in quick on tun0 from 20.20.20.0/24 to any
+ pass in all
+
+2.7. Bi-Directional Filtering; The "out" Keyword
+
+ Up until now, we've been passing or blocking inbound
+traffic. To clarify, inbound traffic is all traffic that
+enters the firewall on any interface. Conversely, outbound
+traffic is all traffic that leaves on any interface (whether
+locally generated or simply passing through). This means
+that all packets coming in are not only filtered as they
+enter the firewall, they're also filtered as they exit.
+Thusfar there's been an implied pass out all that may or may
+not be desirable. Just as you may pass and block incoming
+traffic, you may do the same with outgoing traffic.
+
+ Now that we know there's a way to filter outbound pack-
+ets just like inbound, it's up to us to find a conceivable
+use for such a thing. One possible use of this idea is to
+keep spoofed packets from exiting your own network. Instead
+of passing any traffic out the router, you could instead
+limit permitted traffic to packets originating at
+
+
+
+
+
+
+
+
+
+
+ -9-
+
+
+20.20.20.0/24. You might do it like this:
+
+ pass out quick on tun0 from 20.20.20.0/24 to any
+ block out quick on tun0 from any to any
+
+If a packet comes from 20.20.20.1/32, it gets sent out by
+the first rule. If a packet comes from 1.2.3.4/32 it gets
+blocked by the second.
+
+ You can also make similar rules for the unroutable
+addresses. If some machine tries to route a packet through
+IPF with a destination in 192.168.0.0/16, why not drop it?
+The worst that can happen is that you'll spare yourself some
+bandwidth:
+
+ block out quick on tun0 from any to 192.168.0.0/16
+ block out quick on tun0 from any to 172.16.0.0/12
+ block out quick on tun0 from any to 10.0.0.0/8
+ block out quick on tun0 from any to 0.0.0.0/8
+ block out quick on tun0 from any to 127.0.0.0/8
+ block out quick on tun0 from any to 169.254.0.0/16
+ block out quick on tun0 from any to 192.0.2.0/24
+ block out quick on tun0 from any to 204.152.64.0/23
+ block out quick on tun0 from any to 224.0.0.0/3
+ block out quick on tun0 from !20.20.20.0/24 to any
+
+In the narrowest viewpoint, this doesn't enhance your secu-
+rity. It enhances everybody else's security, and that's a
+nice thing to do. As another viewpoint, one might suppose
+that because nobody can send spoofed packets from your site,
+that your site has less value as a relay for crackers, and
+as such is less of a target.
+
+ You'll likely find a number of uses for blocking out-
+bound packets. One thing to always keep in mind is that in
+and out directions are in reference to your firewall, never
+any other machine.
+
+2.8. Logging What Happens; The "log" Keyword
+
+ Up to this point, all blocked and passed packets have
+been silently blocked and silently passed. Usually you want
+to know if you're being attacked rather than wonder if that
+firewall is really buying you any added benefits. While I
+wouldn't want to log every passed packet, and in some cases
+every blocked packet, I would want to know about the blocked
+packets from 20.20.20.0/24. To do this, we add the log key-
+word:
+
+ block in quick on tun0 from 192.168.0.0/16 to any
+-----------
+ This can, of course, be changed by using -DIPFIL-
+TER_DEFAULT_BLOCK when compiling ipfilter on your
+system.
+
+
+
+
+
+
+
+
+
+ -10-
+
+
+ block in quick on tun0 from 172.16.0.0/12 to any
+ block in quick on tun0 from 10.0.0.0/8 to any
+ block in quick on tun0 from 127.0.0.0/8 to any
+ block in quick on tun0 from 0.0.0.0/8 to any
+ block in quick on tun0 from 169.254.0.0/16 to any
+ block in quick on tun0 from 192.0.2.0/24 to any
+ block in quick on tun0 from 204.152.64.0/23 to any
+ block in quick on tun0 from 224.0.0.0/3 to any
+ block in log quick on tun0 from 20.20.20.0/24 to any
+ pass in all
+
+So far, our firewall is pretty good at blocking packets com-
+ing to it from suspect places, but there's still more to be
+done. For one thing, we're accepting packets destined any-
+where. One thing we ought to do is make sure packets to
+20.20.20.0/32 and 20.20.20.255/32 get dropped on the floor.
+To do otherwise opens the internal network for a smurf
+attack. These two lines would prevent our hypothetical net-
+work from being used as a smurf relay:
+
+ block in log quick on tun0 from any to 20.20.20.0/32
+ block in log quick on tun0 from any to 20.20.20.255/32
+
+This brings our total ruleset to look something like this:
+
+ block in quick on tun0 from 192.168.0.0/16 to any
+ block in quick on tun0 from 172.16.0.0/12 to any
+ block in quick on tun0 from 10.0.0.0/8 to any
+ block in quick on tun0 from 127.0.0.0/8 to any
+ block in quick on tun0 from 0.0.0.0/8 to any
+ block in quick on tun0 from 169.254.0.0/16 to any
+ block in quick on tun0 from 192.0.2.0/24 to any
+ block in quick on tun0 from 204.152.64.0/23 to any
+ block in quick on tun0 from 224.0.0.0/3 to any
+ block in log quick on tun0 from 20.20.20.0/24 to any
+ block in log quick on tun0 from any to 20.20.20.0/32
+ block in log quick on tun0 from any to 20.20.20.255/32
+ pass in all
+
+2.9. Complete Bi-Directional Filtering By Interface
+
+ So far we have only presented fragments of a complete
+ruleset. When you're actually creating your ruleset, you
+should setup rules for every direction and every interface.
+The default state of ipfilter is to pass packets. It is as
+though there were an invisible rule at the beginning which
+states pass in all and pass out all. Rather than rely on
+some default behaviour, make everything as specific as pos-
+sible, interface by interface, until every base is covered.
+
+ First we'll start with the lo0 interface, which wants
+to run wild and free. Since these are programs talking to
+others on the local system, go ahead and keep it unre-
+stricted:
+
+
+
+
+
+
+
+
+
+ -11-
+
+
+ pass out quick on lo0
+ pass in quick on lo0
+
+Next, there's the xl0 interface. Later on we'll begin plac-
+ing restrictions on the xl0 interface, but to start with,
+we'll act as though everything on our local network is
+trustworthy and give it much the same treatment as lo0:
+
+ pass out quick on xl0
+ pass in quick on xl0
+
+Finally, there's the tun0 interface, which we've been half-
+filtering with up until now:
+
+ block out quick on tun0 from any to 192.168.0.0/16
+ block out quick on tun0 from any to 172.16.0.0/12
+ block out quick on tun0 from any to 127.0.0.0/8
+ block out quick on tun0 from any to 10.0.0.0/8
+ block out quick on tun0 from any to 0.0.0.0/8
+ block out quick on tun0 from any to 169.254.0.0/16
+ block out quick on tun0 from any to 192.0.2.0/24
+ block out quick on tun0 from any to 204.152.64.0/23
+ block out quick on tun0 from any to 224.0.0.0/3
+ pass out quick on tun0 from 20.20.20.0/24 to any
+ block out quick on tun0 from any to any
+
+ block in quick on tun0 from 192.168.0.0/16 to any
+ block in quick on tun0 from 172.16.0.0/12 to any
+ block in quick on tun0 from 10.0.0.0/8 to any
+ block in quick on tun0 from 127.0.0.0/8 to any
+ block in quick on tun0 from 0.0.0.0/8 to any
+ block in quick on tun0 from 169.254.0.0/16 to any
+ block in quick on tun0 from 192.0.2.0/24 to any
+ block in quick on tun0 from 204.152.64.0/23 to any
+ block in quick on tun0 from 224.0.0.0/3 to any
+ block in log quick on tun0 from 20.20.20.0/24 to any
+ block in log quick on tun0 from any to 20.20.20.0/32
+ block in log quick on tun0 from any to 20.20.20.255/32
+ pass in all
+
+This is a pretty significant amount of filtering already,
+protecting 20.20.20.0/24 from being spoofed or being used
+for spoofing. Future examples will continue to show one-
+sideness, but keep in mind that it's for brevity's sake, and
+when setting up your own ruleset, adding rules for every
+direction and every interface is necessary.
+
+
+2.10. Controlling Specific Protocols; The "proto" Keyword
+
+ Denial of Service attacks are as rampant as buffer
+overflow exploits. Many denial of service attacks rely on
+glitches in the OS's TCP/IP stack. Frequently, this has
+come in the form of ICMP packets. Why not block them
+
+
+
+
+
+
+
+
+
+ -12-
+
+
+entirely?
+
+ block in log quick on tun0 proto icmp from any to any
+
+Now any ICMP traffic coming in from tun0 will be logged and
+discarded.
+
+2.11. Filtering ICMP with the "icmp-type" Keyword; Merging
+Rulesets
+
+ Of course, dropping all ICMP isn't really an ideal sit-
+uation. Why not drop all ICMP? Well, because it's useful
+to have partially enabled. So maybe you want to keep some
+types of ICMP traffic and drop other kinds. If you want
+ping and traceroute to work, you need to let in ICMP types 0
+and 11. Strictly speaking, this might not be a good idea,
+but if you need to weigh security against convenience, IPF
+lets you do it.
+
+ pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0
+ pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11
+
+Remember that ruleset order is important. Since we're doing
+everything quick we must have our passes before our blocks,
+so we really want the last three rules in this order:
+
+ pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0
+ pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11
+ block in log quick on tun0 proto icmp from any to any
+
+Adding these 3 rules to the anti-spoofing rules is a bit
+tricky. One error might be to put the new ICMP rules at the
+beginning:
+
+ pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0
+ pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11
+ block in log quick on tun0 proto icmp from any to any
+ block in quick on tun0 from 192.168.0.0/16 to any
+ block in quick on tun0 from 172.16.0.0/12 to any
+ block in quick on tun0 from 10.0.0.0/8 to any
+ block in quick on tun0 from 127.0.0.0/8 to any
+ block in quick on tun0 from 0.0.0.0/8 to any
+ block in quick on tun0 from 169.254.0.0/16 to any
+ block in quick on tun0 from 192.0.2.0/24 to any
+ block in quick on tun0 from 204.152.64.0/23 to any
+ block in quick on tun0 from 224.0.0.0/3 to any
+ block in log quick on tun0 from 20.20.20.0/24 to any
+ block in log quick on tun0 from any to 20.20.20.0/32
+ block in log quick on tun0 from any to 20.20.20.255/32
+ pass in all
+
+The problem with this is that an ICMP type 0 packet from
+192.168.0.0/16 will get passed by the first rule, and never
+blocked by the fourth rule. Also, since we quickly pass an
+
+
+
+
+
+
+
+
+
+ -13-
+
+
+ICMP ECHO_REPLY (type 0) to 20.20.20.0/24, we've just opened
+ourselves back up to a nasty smurf attack and nullified
+those last two block rules. Oops. To avoid this, we place
+the ICMP rules after the anti-spoofing rules:
+
+ block in quick on tun0 from 192.168.0.0/16 to any
+ block in quick on tun0 from 172.16.0.0/12 to any
+ block in quick on tun0 from 10.0.0.0/8 to any
+ block in quick on tun0 from 127.0.0.0/8 to any
+ block in quick on tun0 from 0.0.0.0/8 to any
+ block in quick on tun0 from 169.254.0.0/16 to any
+ block in quick on tun0 from 192.0.2.0/24 to any
+ block in quick on tun0 from 204.152.64.0/23 to any
+ block in quick on tun0 from 224.0.0.0/3 to any
+ block in log quick on tun0 from 20.20.20.0/24 to any
+ block in log quick on tun0 from any to 20.20.20.0/32
+ block in log quick on tun0 from any to 20.20.20.255/32
+ pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0
+ pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11
+ block in log quick on tun0 proto icmp from any to any
+ pass in all
+
+Because we block spoofed traffic before the ICMP rules are
+processed, a spoofed packet never makes it to the ICMP rule-
+set. It's very important to keep such situations in mind
+when merging rules.
+
+2.12. TCP and UDP Ports; The "port" Keyword
+
+ Now that we've started blocking packets based on proto-
+col, we can start blocking packets based on specific aspects
+of each protocol. The most frequently used of these aspects
+is the port number. Services such as rsh, rlogin, and tel-
+net are all very convenient to have, but also hideously
+insecure against network sniffing and spoofing. One great
+compromise is to only allow the services to run internally,
+then block them externally. This is easy to do because
+rlogin, rsh, and telnet use specific TCP ports (513, 514,
+and 23 respectively). As such, creating rules to block them
+is easy:
+
+ block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 513
+ block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 514
+ block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 23
+
+Make sure all 3 are before the pass in all and they'll be
+closed off from the outside (leaving out spoofing for
+brevity's sake):
+
+ pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 0
+ pass in quick on tun0 proto icmp from any to 20.20.20.0/24 icmp-type 11
+ block in log quick on tun0 proto icmp from any to any
+ block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 513
+ block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 514
+
+
+
+
+
+
+
+
+
+ -14-
+
+
+ block in log quick on tun0 proto tcp from any to 20.20.20.0/24 port = 23
+ pass in all
+
+You might also want to block 514/udp (syslog), 111/tcp &
+111/udp (portmap), 515/tcp (lpd), 2049/tcp and 2049/udp
+(NFS), 6000/tcp (X11) and so on and so forth. You can get a
+complete listing of the ports being listened to by using
+netstat -a (or lsof -i, if you have it installed).
+
+ Blocking UDP instead of TCP only requires replacing
+proto tcp with proto udp. The rule for syslog would be:
+
+ block in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 514
+
+IPF also has a shorthand way to write rules that apply to
+both proto tcp and proto udp at the same time, such as
+portmap or NFS. The rule for portmap would be:
+
+ block in log quick on tun0 proto tcp/udp from any to 20.20.20.0/24 port = 111
+
+
+
+
+3. Advanced Firewalling Introduction
+
+ This section is designed as an immediate followup to
+the basic section. Contained below are both concepts for
+advanced firewall design, and advanced features contained
+only within ipfilter. Once you are comfortable with this
+section, you should be able to build a very strong firewall.
+
+3.1. Rampant Paranoia; or The Default-Deny Stance
+
+ There's a big problem with blocking services by the
+port: sometimes they move. RPC based programs are terrible
+about this, lockd, statd, even nfsd listens places other
+than 2049. It's awfully hard to predict, and even worse to
+automate adjusting all the time. What if you miss a ser-
+vice? Instead of dealing with all that hassle, let's start
+over with a clean slate. The current ruleset looks like
+this:
+
+
+
+
+ Yes, we really are starting over. The first rule we're
+going to use is this:
+
+ block in all
+
+No network traffic gets through. None. Not a peep. You're
+rather secure with this setup. Not terribly useful, but
+quite secure. The great thing is that it doesn't take much
+more to make your box rather secure, yet useful too. Let's
+
+
+
+
+
+
+
+
+
+ -15-
+
+
+say the machine this is running on is a web server, nothing
+more, nothing less. It doesn't even do DNS lookups. It
+just wants to take connections on 80/tcp and that's it. We
+can do that. We can do that with a second rule, and you
+already know how:
+
+ block in on tun0 all
+ pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 80
+
+This machine will pass in port 80 traffic for 20.20.20.1,
+and deny everything else. For basic firewalling, this is
+all one needs.
+
+3.2. Implicit Allow; The "keep state" Rule
+
+ The job of your firewall is to prevent unwanted traffic
+getting to point B from point A. We have general rules
+which say "as long as this packet is to port 23, it's okay."
+We have general rules which say "as long as this packet has
+its FIN flag set, it's okay." Our firewalls don't know the
+beginning, middle, or end of any TCP/UDP/ICMP session. They
+merely have vague rules that are applied to all packets.
+We're left to hope that the packet with its FIN flag set
+isn't really a FIN scan, mapping our services. We hope that
+the packet to port 23 isn't an attempted hijack of our tel-
+net session. What if there was a way to identify and autho-
+rize individual TCP/UDP/ICMP sessions and distinguish them
+from port scanners and DoS attacks? There is a way, it's
+called keeping state.
+
+ We want convenience and security in one. Lots of peo-
+ple do, that's why Ciscos have an "established" clause that
+lets established tcp sessions go through. Ipfw has estab-
+lished. Ipfwadm has setup/established. They all have this
+feature, but the name is very misleading. When we first saw
+it, we thought it meant our packet filter was keeping track
+of what was going on, that it knew if a connection was
+really established or not. The fact is, they're all taking
+the packet's word for it from a part of the packet anybody
+can lie about. They read the TCP packet's flags section and
+there's the reason UDP/ICMP don't work with it, they have no
+such thing. Anybody who can create a packet with bogus
+flags can get by a firewall with this setup.
+
+ Where does IPF come in to play here, you ask? Well,
+unlike the other firewalls, IPF really can keep track of
+whether or not a connection is established. And it'll do it
+with TCP, UDP and ICMP, not just TCP. Ipf calls it keeping
+state. The keyword for the ruleset is keep state.
+
+ Up until now, we've told you that packets come in, then
+the ruleset gets checked; packets go out, then the ruleset
+gets checked. Actually, what happens is packets come in,
+the state table gets checked, then *maybe* the inbound
+
+
+
+
+
+
+
+
+
+ -16-
+
+
+ruleset gets checked; packets go out, the state table gets
+checked, then *maybe* the outbound ruleset gets checked.
+The state table is a list of TCP/UDP/ICMP sessions that are
+unquestionadely passed through the firewall, circumventing
+the entire ruleset. Sound like a serious security hole?
+Hang on, it's the best thing that ever happened to your
+firewall.
+
+ All TCP/IP sessions have a start, a middle, and an end
+(even though they're sometimes all in the same packet). You
+can't have an end without a middle and you can't have a mid-
+dle without a start. This means that all you really need to
+filter on is the beginning of a TCP/UDP/ICMP session. If
+the beginning of the session is allowed by your firewall
+rules, you really want the middle and end to be allowed too
+(lest your IP stack should overflow and your machines become
+useless). Keeping state allows you to ignore the middle and
+end and simply focus on blocking/passing new sessions. If
+the new session is passed, all its subsequent packets will
+be allowed through. If it's blocked, none of its subsequent
+packets will be allowed through. Here's an example for run-
+ning an ssh server (and nothing but an ssh server):
+
+ block out quick on tun0 all
+ pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 22 keep state
+
+The first thing you might notice is that there's no "pass
+out" provision. In fact, there's only an all-inclusive
+"block out" rule. Despite this, the ruleset is complete.
+This is because by keeping state, the entire ruleset is cir-
+cumvented. Once the first SYN packet hits the ssh server,
+state is created and the remainder of the ssh session is
+allowed to take place without interference from the fire-
+wall. Here's another example:
+
+ block in quick on tun0 all
+ pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state
+
+In this case, the server is running no services. Infact,
+it's not a server, it's a client. And this client doesn't
+want unauthorized packets entering its IP stack at all.
+However, the client wants full access to the internet and
+the reply packets that such privilege entails. This simple
+ruleset creates state entries for every new outgoing TCP
+session. Again, since a state entry is created, these new
+TCP sessions are free to talk back and forth as they please
+without the hindrance or inspection of the firewall rule-
+set. We mentioned that this also works for UDP and ICMP:
+
+ block in quick on tun0 all
+ pass out quick on tun0 proto tcp from 20.20.20.1/32 to any keep state
+ pass out quick on tun0 proto udp from 20.20.20.1/32 to any keep state
+ pass out quick on tun0 proto icmp from 20.20.20.1/32 to any keep state
+
+
+
+
+
+
+
+
+
+
+ -17-
+
+
+Yes Virginia, we can ping. Now we're keeping state on TCP,
+UDP, ICMP. Now we can make outgoing connections as though
+there's no firewall at all, yet would-be attackers can't get
+back in. This is very handy because there's no need to
+track down what ports we're listening to, only the ports we
+want people to be able to get to.
+
+ State is pretty handy, but it's also a bit tricky. You
+can shoot yourself in the foot in strange and mysterious
+ways. Consider the following ruleset:
+
+ pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23
+ pass out quick on tun0 proto tcp from any to any keep state
+ block in quick all
+ block out quick all
+
+At first glance, this seems to be a good setup. We allow
+incoming sessions to port 23, and outgoing sessions any-
+where. Naturally packets going to port 23 will have reply
+packets, but the ruleset is setup in such a way that the
+pass out rule will generate a state entry and everything
+will work perfectly. At least, you'd think so.
+
+ The unfortunate truth is that after 60 seconds of idle
+time the state entry will be closed (as opposed to the nor-
+mal 5 days). This is because the state tracker never saw
+the original SYN packet destined to port 23, it only saw the
+SYN ACK. IPF is very good about following TCP sessions from
+start to finish, but it's not very good about coming into
+the middle of a connection, so rewrite the rule to look like
+this:
+
+ pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 keep state
+ pass out quick on tun0 proto tcp from any to any keep state
+ block in quick all
+ block out quick all
+
+The additional of this rule will enter the very first packet
+into the state table and everything will work as expected.
+Once the 3-way handshake has been witness by the state
+engine, it is marked in 4/4 mode, which means it's setup for
+long-term data exchange until such time as the connection is
+torn down (wherein the mode changes again. You can see the
+current modes of your state table with ipfstat -s.
+
+3.3. Stateful UDP
+
+ UDP is stateless so naturally it's a bit harder to do a
+reliable job of keeping state on it. Nonetheless, ipf does
+a pretty good job. When machine A sends a UDP packet to
+machine B with source port X and destination port Y, ipf
+will allow a reply from machine B to machine A with source
+port Y and destination port X. This is a short term state
+entry, a mere 60 seconds.
+
+
+
+
+
+
+
+
+
+ -18-
+
+
+ Here's an example of what happens if we use nslookup to
+get the IP address of www.3com.com:
+
+ $ nslookup www.3com.com
+
+ A DNS packet is generated:
+
+ 17:54:25.499852 20.20.20.1.2111 > 198.41.0.5.53: 51979+
+
+The packet is from 20.20.20.1, port 2111, destined for
+198.41.0.5, port 53. A 60 second state entry is created.
+If a packet comes back from 198.41.0.5 port 53 destined for
+20.20.20.1 port 2111 within that period of time, the reply
+packet will be let through. As you can see, milliseconds
+later:
+
+ 17:54:25.501209 198.41.0.5.53 > 20.20.20.1.2111: 51979 q: www.3com.com
+
+The reply packet matches the state criteria and is let
+through. At that same moment that packet is let through,
+the state gateway is closed and no new incoming packets will
+be allowed in, even if they claim to be from the same place.
+
+3.4. Stateful ICMP
+
+ IPFilter handles ICMP states in the manner that one
+would expect from understanding how ICMP is used with TCP
+and UDP, and with your understanding of how keep state
+works. There are two general types of ICMP messages;
+requests and replies. When you write a rule such as:
+
+ pass out on tun0 proto icmp from any to any icmp-type 8 keep state
+
+to allow outbound echo requests (a typical ping), the resul-
+tant icmp-type 0 packet that comes back will be allowed in.
+This state entry has a default timeout of an incomplete 0/0
+state of 60 seconds. Thus, if you are keeping state on any
+outbound icmp message that will elicit an icmp message in
+reply, you need a proto icmp [...] keep state rule.
+
+ However, the majority of ICMP messages are status mes-
+sages generated by some failure in UDP (and sometimes TCP),
+and in 3.4.x and greater IPFilters, any ICMP error status
+message (say icmp-type 3 code 3 port unreachable, or icmp-
+type 11 time exceeded) that matches an active state table
+entry that could have generated that message, the ICMP
+packet is let in. For example, in older IPFilters, if you
+wanted traceroute to work, you needed to use:
+
+ pass out on tun0 proto udp from any to any port 33434><33690 keep state
+ pass in on tun0 proto icmp from any to any icmp-type timex
+
+whereas now you can do the right thing and just keep state
+on udp with:
+
+
+
+
+
+
+
+
+
+ -19-
+
+
+ pass out on tun0 proto udp from any to any port 33434><33690 keep state
+
+To provide some protection against a third-party sneaking
+ICMP messages through your firewall when an active connec-
+tion is known to be in your state table, the incoming ICMP
+packet is checked not only for matching source and destina-
+tion addresses (and ports, when applicable) but a tiny part
+of the payload of the packet that the ICMP message is claim-
+ing it was generated by.
+
+3.5. FIN Scan Detection; "flags" Keyword, "keep frags" Key-
+word
+
+Let's go back to the 4 rule set from the previous section:
+
+ pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 keep state
+ pass out quick on tun0 proto tcp from any to any keep state
+ block in quick all
+ block out quick all
+
+This is almost, but not quite, satisfactory. The problem is
+that it's not just SYN packets that're allowed to go to port
+23, any old packet can get through. We can change this by
+using the flags option:
+
+ pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state
+ pass out quick on tun0 proto tcp from any to any flags S keep state
+ block in quick all
+ block out quick all
+
+Now only TCP packets, destined for 20.20.20.1, at port 23,
+with a lone SYN flag will be allowed in and entered into the
+state table. A lone SYN flag is only present as the very
+first packet in a TCP session (called the TCP handshake) and
+that's really what we wanted all along. There's at least
+two advantages to this: No arbitrary packets can come in
+and make a mess of your state table. Also, FIN and XMAS
+scans will fail since they set flags other than the SYN
+flag. Now all incoming packets must either be handshakes or
+have state already. If anything else comes in, it's proba-
+bly a port scan or a forged packet. There's one exception
+to that, which is when a packet comes in that's fragmented
+from its journey. IPF has provisions for this as well, the
+-----------
+ Some examples use flags S/SA instead of flags S.
+flags S actually equates to flags S/AUPRFS and
+matches against only the SYN packet out of all six
+possible flags, while flags S/SA will allow pack-
+ets that may or may not have the URG, PSH, FIN, or
+RST flags set. Some protocols demand the URG or
+PSH flags, and S/SAFR would be a better choice for
+these, however we feel that it is less secure to
+blindly use S/SA when it isn't required. But it's
+your firewall.
+
+
+
+
+
+
+
+
+
+ -20-
+
+
+keep frags keyword. With it, IPF will notice and keep track
+of packets that are fragmented, allowing the expected frag-
+ments to go through. Let's rewrite the 3 rules to log
+forgeries and allow fragments:
+
+ pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 23 flags S keep state keep frags
+ pass out quick on tun0 proto tcp from any to any keep state flags S keep frags
+ block in log quick all
+ block out log quick all
+
+This works because every packet that should be allowed
+through makes it into the state table before the blocking
+rules are reached. The only scan this won't detect is a SYN
+scan itself. If you're truly worried about that, you might
+even want to log all initial SYN packets.
+
+3.6. Responding To a Blocked Packet
+
+ So far, all of our blocked packets have been dumped on
+the floor, logged or not, we've never sent anything back to
+the originating host. Sometimes this isn't the most desir-
+able of responses because in doing so, we actually tell the
+attacker that a packet filter is present. It seems a far
+better thing to misguide the attacker into believing that,
+while there's no packet filter running, there's likewise no
+services to break into. This is where fancier blocking
+comes into play.
+
+ When a service isn't running on a Unix system, it nor-
+mally lets the remote host know with some sort of return
+packet. In TCP, this is done with an RST (Reset) packet.
+When blocking a TCP packet, IPF can actually return an RST
+to the origin by using the return-rst keyword.
+
+Where once we did:
+
+ block in log on tun0 proto tcp from any to 20.20.20.0/24 port = 23
+ pass in all
+
+We might now do:
+
+ block return-rst in log proto tcp from any to 20.20.20.0/24 port = 23
+ block in log quick on tun0
+ pass in all
+
+We need two block statements since return-rst only works
+with TCP, and we still want to block protocols such as UDP,
+ICMP, and others. Now that this is done, the remote side
+will get "connection refused" instead of "connection timed
+out".
+
+ It's also possible to send an error message when some-
+body sends a packet to a UDP port on your system. Whereas
+once you might have used:
+
+
+
+
+
+
+
+
+
+ -21-
+
+
+ block in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111
+
+You could instead use the return-icmp keyword to send a
+reply:
+
+ block return-icmp(port-unr) in log quick on tun0 proto udp from any to 20.20.20.0/24 port = 111
+
+According to TCP/IP Illustrated, port-unreachable is the
+correct ICMP type to return when no service is listening on
+the port in question. You can use any ICMP type you like,
+but port-unreachable is probably your best bet. It's also
+the default ICMP type for return-icmp.
+
+ However, when using return-icmp, you'll notice that
+it's not very stealthy, and it returns the ICMP packet with
+the IP address of the firewall, not the original destination
+of the packet. This was fixed in ipfilter 3.3, and a new
+keyword; return-icmp-as-dest, has been added. The new for-
+mat is:
+
+ block return-icmp-as-dest(port-unr) in log on tun0 proto udp from any to 20.20.20.0/24 port = 111
+
+3.7. Fancy Logging Techniques
+
+ It is important to note that the presence of the log
+keyword only ensures that the packet will be available to
+the ipfilter logging device; /dev/ipl. In order to actu-
+ally see this log information, one must be running the ipmon
+utility (or some other utility that reads from /dev/ipl).
+The typical usage of log is coupled with ipmon -s to log the
+information to syslog. As of ipfilter 3.3, one can now even
+control the logging behavior of syslog by using log level
+keywords, as in rules such as this:
+
+ block in log level auth.info quick on tun0 from 20.20.20.0/24 to any
+ block in log level auth.alert quick on tun0 proto tcp from any to 20.20.20.0/24 port = 21
+
+In addition to this, you can tailor what information is
+being logged. For example, you may not be interested that
+someone attempted to probe your telnet port 500 times, but
+you are interested that they probed you once. You can use
+the log first keyword to only log the first example of a
+packet. Of course, the notion of "first-ness" only applies
+to packets in a specific session, and for the typical
+blocked packet, you will be hard pressed to encounter situa-
+tions where this does what you expect. However, if used in
+conjunction with pass and keep state, this can be a valuable
+keyword for keeping tabs on traffic.
+
+ Another useful thing you can do with the logs is to
+keep track of interesting pieces of the packet in addition
+to the header information normally being logged. Ipfilter
+will give you the first 128 bytes of the packet if you use
+the log body keyword. You should limit the use of body
+
+
+
+
+
+
+
+
+
+ -22-
+
+
+logging, as it makes your logs very verbose, but for certain
+applications, it is often handy to be able to go back and
+take a look at the packet, or to send this data to another
+application that can examine it further.
+
+3.8. Putting It All Together
+
+ So now we have a pretty tight firewall, but it can
+still be tighter. Some of the original ruleset we wiped
+clean is actually very useful. I'd suggest bringing back
+all the anti-spoofing stuff. This leaves us with:
+
+ block in on tun0
+ block in quick on tun0 from 192.168.0.0/16 to any
+ block in quick on tun0 from 172.16.0.0/12 to any
+ block in quick on tun0 from 10.0.0.0/8 to any
+ block in quick on tun0 from 127.0.0.0/8 to any
+ block in quick on tun0 from 0.0.0.0/8 to any
+ block in quick on tun0 from 169.254.0.0/16 to any
+ block in quick on tun0 from 192.0.2.0/24 to any
+ block in quick on tun0 from 204.152.64.0/23 to any
+ block in quick on tun0 from 224.0.0.0/3 to any
+ block in log quick on tun0 from 20.20.20.0/24 to any
+ block in log quick on tun0 from any to 20.20.20.0/32
+ block in log quick on tun0 from any to 20.20.20.255/32
+ pass out quick on tun0 proto tcp/udp from 20.20.20.1/32 to any keep state
+ pass out quick on tun0 proto icmp from 20.20.20.1/32 to any keep state
+ pass in quick on tun0 proto tcp from any to 20.20.20.1/32 port = 80 flags S keep state
+
+3.9. Improving Performance With Rule Groups
+
+ Let's extend our use of our firewall by creating a much
+more complicated, and we hope more applicable to the real
+world, example configuration For this example, we're going
+to change the interface names, and network numbers. Let's
+assume that we have three interfaces in our firewall with
+interfaces xl0, xl1, and xl2.
+
+xl0 is connected to our external network 20.20.20.0/26
+xl1 is connected to our "DMZ" network 20.20.20.64/26
+xl2 is connected to our protected network 20.20.20.128/25
+
+We'll define the entire ruleset in one swoop, since we fig-
+ure that you can read these rules by now:
+
+ block in quick on xl0 from 192.168.0.0/16 to any
+ block in quick on xl0 from 172.16.0.0/12 to any
+ block in quick on xl0 from 10.0.0.0/8 to any
+ block in quick on xl0 from 127.0.0.0/8 to any
+ block in quick on xl0 from 0.0.0.0/8 to any
+ block in quick on xl0 from 169.254.0.0/16 to any
+ block in quick on xl0 from 192.0.2.0/24 to any
+ block in quick on xl0 from 204.152.64.0/23 to any
+ block in quick on xl0 from 224.0.0.0/3 to any
+
+
+
+
+
+
+
+
+
+ -23-
+
+
+ block in log quick on xl0 from 20.20.20.0/24 to any
+ block in log quick on xl0 from any to 20.20.20.0/32
+ block in log quick on xl0 from any to 20.20.20.63/32
+ block in log quick on xl0 from any to 20.20.20.64/32
+ block in log quick on xl0 from any to 20.20.20.127/32
+ block in log quick on xl0 from any to 20.20.20.128/32
+ block in log quick on xl0 from any to 20.20.20.255/32
+ pass out on xl0 all
+
+ pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state
+ pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 21 flags S keep state
+ pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 20 flags S keep state
+ pass out quick on xl1 proto tcp from any to 20.20.20.65/32 port = 53 flags S keep state
+ pass out quick on xl1 proto udp from any to 20.20.20.65/32 port = 53 keep state
+ pass out quick on xl1 proto tcp from any to 20.20.20.66/32 port = 53 flags S keep state
+ pass out quick on xl1 proto udp from any to 20.20.20.66/32 port = 53 keep state
+ block out on xl1 all
+ pass in quick on xl1 proto tcp/udp from 20.20.20.64/26 to any keep state
+
+ block out on xl2 all
+ pass in quick on xl2 proto tcp/udp from 20.20.20.128/25 to any keep state
+
+From this arbitarary example, we can already see that our
+ruleset is becoming unwieldy. To make matters worse, as we
+add more specific rules to our DMZ network, we add addi-
+tional tests that must be parsed for every packet, which
+affects the performance of the xl0 <-> xl2 connections. If
+you set up a firewall with a ruleset like this, and you have
+lots of bandwidth and a moderate amount of cpu, everyone
+that has a workstation on the xl2 network is going to come
+looking for your head to place on a platter. So, to keep
+your head <-> torso network intact, you can speed things
+along by creating rule groups. Rule groups allow you to
+write your ruleset in a tree fashion, instead of as a linear
+list, so that if your packet has nothing to do with the set
+of tests (say, all those xl1 rules) those rules will never
+be consulted. It's somewhat like having multiple firewalls
+all on the same machine.
+
+Here's a simple example to get us started:
+
+ block out quick on xl1 all head 10
+ pass out quick proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state group 10
+ block out on xl2 all
+
+In this simplistic example, we can see a small hint of the
+power of the rule group. If the packet is not destined for
+xl1, the head of rule group 10 will not match, and we will
+go on with our tests. If the packet does match for xl1, the
+quick keyword will short-circuit all further processing at
+the root level (rule group 0), and focus the testing on
+rules which belong to group 10; namely, the SYN check for
+80/tcp. In this way, we can re-write the above rules so
+that we can maximize performance of our firewall.
+
+
+
+
+
+
+
+
+
+ -24-
+
+
+ block in quick on xl0 all head 1
+ block in quick on xl0 from 192.168.0.0/16 to any group 1
+ block in quick on xl0 from 172.16.0.0/12 to any group 1
+ block in quick on xl0 from 10.0.0.0/8 to any group 1
+ block in quick on xl0 from 127.0.0.0/8 to any group 1
+ block in quick on xl0 from 0.0.0.0/8 to any group 1
+ block in quick on xl0 from 169.254.0.0/16 to any group 1
+ block in quick on xl0 from 192.0.2.0/24 to any group 1
+ block in quick on xl0 from 204.152.64.0/23 to any group 1
+ block in quick on xl0 from 224.0.0.0/3 to any group 1
+ block in log quick on xl0 from 20.20.20.0/24 to any group 1
+ block in log quick on xl0 from any to 20.20.20.0/32 group 1
+ block in log quick on xl0 from any to 20.20.20.63/32 group 1
+ block in log quick on xl0 from any to 20.20.20.64/32 group 1
+ block in log quick on xl0 from any to 20.20.20.127/32 group 1
+ block in log quick on xl0 from any to 20.20.20.128/32 group 1
+ block in log quick on xl0 from any to 20.20.20.255/32 group 1
+ pass in on xl0 all group 1
+
+ pass out on xl0 all
+
+ block out quick on xl1 all head 10
+ pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 80 flags S keep state group 10
+ pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 21 flags S keep state group 10
+ pass out quick on xl1 proto tcp from any to 20.20.20.64/26 port = 20 flags S keep state group 10
+ pass out quick on xl1 proto tcp from any to 20.20.20.65/32 port = 53 flags S keep state group 10
+ pass out quick on xl1 proto udp from any to 20.20.20.65/32 port = 53 keep state group 10
+ pass out quick on xl1 proto tcp from any to 20.20.20.66/32 port = 53 flags S keep state
+ pass out quick on xl1 proto udp from any to 20.20.20.66/32 port = 53 keep state group 10
+
+ pass in quick on xl1 proto tcp/udp from 20.20.20.64/26 to any keep state
+
+ block out on xl2 all
+
+ pass in quick on xl2 proto tcp/udp from 20.20.20.128/25 to any keep state
+
+Now you can see the rule groups in action. For a host on
+the xl2 network, we can completely bypass all the checks in
+group 10 when we're not communicating with hosts on that
+network.
+
+ Depending on your situation, it may be prudent to group
+your rules by protocol, or various machines, or netblocks,
+or whatever makes it flow smoothly.
+
+3.10. "Fastroute"; The Keyword of Stealthiness
+
+ Even though we're forwarding some packets, and blocking
+other packets, we're typically behaving like a well behaved
+router should by decrementing the TTL on the packet and
+acknowledging to the entire world that yes, there is a hop
+here. But we can hide our presence from inquisitive appli-
+cations like unix traceroute which uses UDP packets with
+various TTL values to map the hops between two sites. If we
+
+
+
+
+
+
+
+
+
+ -25-
+
+
+want incoming traceroutes to work, but we do not want to
+announce the presence of our firewall as a hop, we can do so
+with a rule like this:
+
+ block in quick on xl0 fastroute proto udp from any to any port 33434 >< 33465
+
+The presence of the fastroute keyword will signal ipfilter
+to not pass the packet into the Unix IP stack for routing
+which results in a TTL decrement. The packet will be placed
+gently on the output interface by ipfilter itself and no
+such decrement will happen. Ipfilter will of course use the
+system's routing table to figure out what the appropriate
+output interface really is, but it will take care of the
+actual task of routing itself.
+
+ There's a reason we used block quick in our example,
+too. If we had used pass, and if we had IP Forwarding
+enabled in our kernel, we would end up having two paths for
+a packet to come out of, and we would probably panic our
+kernel.
+
+ It should be noted, however, that most Unix kernels
+(and certainly the ones underlying the systems that ipfilter
+usually runs on) have far more efficient routing code than
+what exists in ipfilter, and this keyword should not be
+thought of as a way to improve the operating speed of your
+firewall, and should only be used in places where stealth is
+an issue.
+
+
+
+
+4. NAT and Proxies
+
+ Outside of the corporate environment, one of the
+biggest enticements of firewall technology to the end user
+is the ability to connect several computers through a common
+external interface, often without the approval, knowledge,
+or even consent of their service provider. To those famil-
+iar with Linux, this concept is called IP Masquerading, but
+to the rest of the world it is known by the more obscure
+name of Network Address Translation, or NAT for short.
+
+4.1. Mapping Many Addresses Into One Address
+
+ The basic use of NAT accomplishes much the same thing
+that Linux's IP Masquerading function does, and it does it
+-----------
+ To be pedantic, what IPFilter provides is really
+called NPAT, for Network and Port Address Transla-
+tion, which means we can change any of the source
+and destination IP Addresses and their source and
+destination ports. True NAT only allows one to
+change the addresses.
+
+
+
+
+
+
+
+
+
+ -26-
+
+
+with one simple rule:
+
+ map tun0 192.168.1.0/24 -> 20.20.20.1/32
+
+Very simple. Whenever a packet goes out the tun0 interface
+with a source address matching the CIDR network mask of
+192.168.1.0/24 this packet will be rewritten within the IP
+stack such that its source address is 20.20.20.1, and it
+will be sent on to its original destination. The system
+also keeps a list of what translated connections are in
+progress so that it can perform the reverse and remap the
+response (which will be directed to 20.20.20.1) to the
+internal host that really generated the packet.
+
+ There is a drawback to the rule we have just written,
+though. In a large number of cases, we do not happen to
+know what the IP address of our outside link is (if we're
+using tun0 or ppp0 and a typical ISP) so it makes setting up
+our NAT tables a chore. Luckily, NAT is smart enough to
+accept an address of 0/32 as a signal that it needs to go
+look at what the address of that interface really is and we
+can rewrite our rule as follows:
+
+ map tun0 192.168.1.0/24 -> 0/32
+
+Now we can load our ipnat rules with impunity and connect to
+the outside world without having to edit anything. You do
+have to run ipf -y to refresh the address if you get discon-
+nected and redial or if your DHCP lease changes, though.
+
+ Some of you may be wondering what happens to the source
+port when the mapping happens. With our current rule, the
+packet's source port is unchanged from the original source
+port. There can be instances where we do not desire this
+behavior; maybe we have another firewall further upstream we
+have to pass through, or perhaps many hosts are trying to
+use the same source port, causing a collision where the rule
+doesn't match and the packet is passed untranslated. ipnat
+helps us here with the portmap keyword:
+
+ map tun0 192.168.1.0/24 -> 0/32 portmap tcp/udp 20000:30000
+
+Our rule now shoehorns all the translated connections (which
+can be tcp, udp, or tcp/udp) into the port range of 20000 to
+30000.
+
+
+
+-----------
+ This is a typical internal address space, since
+it's non-routable on the Real Internet it is often
+used for internal networks. You should still
+block these packets coming in from the outside
+world as discussed earlier.
+
+
+
+
+
+
+
+
+
+ -27-
+
+
+4.2. Mapping Many Addresses Into a Pool of Addresses
+
+ Another use common use of NAT is to take a small stati-
+cally allocated block of addresses and map many computers
+into this smaller address space. This is easy to accom-
+plish using what you already know about the map and portmap
+keywords by writing a rule like so:
+
+ map tun0 192.168.0.0/16 -> 20.20.20.0/24 portmap tcp/udp 20000:60000
+
+Also, there may be instances where a remote application
+requires that multiple connections all come from the same IP
+address. We can help with these situations by telling NAT
+to statically map sessions from a host into the pool of
+addresses and work some magic to choose a port. This uses a
+the keyword map-block as follows:
+
+ map-block tun0 192.168.1.0/24 -> 20.20.20.0/24
+
+4.3. One to One Mappings
+
+ Occasionally it is desirable to have a system with one
+IP address behind the firewall to appear to have a com-
+pletely different IP address. One example of how this would
+work would be a lab of computers which are then attached to
+various networks that are to be put under some kind of test.
+In this example, you would not want to have to reconfigure
+the entire lab when you could place a NAT system in front
+and change the addresses in one simple place. We can do
+that with the bimap keyword, for bidirectional mapping.
+Bimap has some additional protections on it to ensure a
+known state for the connection, whereas the map keyword is
+designed to allocate an address and a source port and
+rewrite the packet and go on with life.
+
+ bimap tun0 192.168.1.1/32 -> 20.20.20.1/32
+
+will accomplish the mapping for one host.
+
+4.4. Spoofing Services
+
+ Spoofing services? What does that have to do with any-
+thing? Plenty. Let's pretend that we have a web server
+running on 20.20.20.5, and since we've gotten increasingly
+suspicious of our network security, we desire to not run
+this server on port 80 since that requires a brief lifespan
+as the root user. But how do we run it on a less
+privledged port of 8000 in this world of "anything dot com"?
+How will anyone find our server? We can use the redirection
+facilities of NAT to solve this problem by instructing it to
+remap any connections destined for 20.20.20.5:80 to really
+point to 20.20.20.5:8000. This uses the rdr keyword:
+
+ rdr tun0 20.20.20.5/32 port 80 -> 192.168.0.5 port 8000
+
+
+
+
+
+
+
+
+
+ -28-
+
+
+We can also specify the protocol here, if we wanted to redi-
+rect a UDP service, instead of a TCP service (which is the
+default). For example, if we had a honeypot on our firewall
+to impersonate the popular Back Orifice for Windows, we
+could shovel our entire network into this one place with a
+simple rule:
+
+ rdr tun0 20.20.20.0/24 port 31337 -> 127.0.0.1 port 31337 udp
+
+An extremely important point must be made about rdr: You
+cannot easily use this feature as a "reflector". E.g:
+
+ rdr tun0 20.20.20.5/32 port 80 -> 20.20.20.6 port 80 tcp
+
+will not work in the situation where .5 and .6 are on the
+same LAN segment. The rdr function is applied to packets
+that enter the firewall on the specified interface. When a
+packet comes in that matches a rdr rule, its destination
+address is then rewritten, it is pushed into ipf for filter-
+ing, and should it successfully run the gauntlet of filter
+rules, it is then sent to the unix routing code. Since this
+packet is still inbound on the same interface that it will
+need to leave the system on to reach a host, the system gets
+confused. Reflectors don't work. Neither does specifying
+the address of the interface the packet just came in on.
+Always remember that rdr destinations must exit out of the
+firewall host on a different interface.
+
+4.5. Transparent Proxy Support; Redirection Made Useful
+
+ Since you're installing a firewall, you may have
+decided that it is prudent to use a proxy for many of your
+outgoing connections so that you can further tighten your
+filter rules protecting your internal network, or you may
+have run into a situation that the NAT mapping process does
+not currently handle properly. This can also be accom-
+plished with a redirection statement:
+
+ rdr xl0 0.0.0.0/0 port 21 -> 127.0.0.1 port 21
+
+This statement says that any packet coming in on the xl0
+interface destined for any address (0.0.0.0/0) on the ftp
+port should be rewritten to connect it with a proxy that is
+running on the NAT system on port 21.
+
+-----------
+ Yes. There is a way to do this. It's so convo-
+luted that I refuse to use it, though. Smart peo-
+ple who require this functionality will transpar-
+ently redirect into something like TIS plug-gw on
+127.0.0.1. Stupid people will set up a dummy loop
+interface pair and double rewrite.
+ This includes 127.0.0.1, by the way. That's on
+lo0. Neat, huh?
+
+
+
+
+
+
+
+
+
+ -29-
+
+
+ This specific example of FTP proxying does lead to some
+complications when used with web browsers or other auto-
+matic-login type clients that are unaware of the require-
+ments of communicating with the proxy. There are patches
+for TIS Firewall Toolkit'sftp-gw to mate it with the nat
+process so that it can determine where you were trying to go
+and automatically send you there. Many proxy packages now
+work in a transparent proxy environment (Squid for example,
+located at http://squid.nlanr.net, works fine.)
+
+ This application of the rdr keyword is often more use-
+ful when you wish to force users to authenticate themselves
+with the proxy. (For example, you desire your engineers to
+be able to surf the web, but you would rather not have your
+call-center staff doing so.)
+
+4.6. Magic Hidden Within NAT; Application Proxies
+
+ Since ipnat provides a method to rewrite packets as
+they traverse the firewall, it becomes a convenient place to
+build in some application level proxies to make up for well
+known deficiencies of that application and typical fire-
+walls. For example; FTP. We can make our firewall pay
+attention to the packets going across it and when it notices
+that it's dealing with an Active FTP session, it can write
+itself some temporary rules, much like what happens with
+keep state, so that the FTP data connection works. To do
+this, we use a rule like so:
+
+ map tun0 192.168.1.0/24 -> 20.20.20.1/32 proxy port ftp ftp/tcp
+
+You must always remember to place this proxy rule before any
+portmap rules, otherwise when portmap comes along and
+matches the packet and rewrites it before the proxy gets a
+chance to work on it. Remember that ipnat rules are first-
+match.
+
+ There also exist proxies for "rcmd" (which we suspect
+is berkeley r-* commands which should be forbidden anyway,
+thus we haven't looked at what this proxy does) and "raudio"
+for Real Audio PNM streams. Likewise, both of these rules
+should be put before any portmap rules, if you're doing NAT.
+
+
+
+5. Loading and Manipulating Filter Rules; The ipf Utility
+
+ IP Filter rules are loaded by using the ipf utility.
+The filter rules can be stored in any file on the system,
+but typically these rules are stored in /etc/ipf.rules,
+/usr/local/etc/ipf.rules, or /etc/opt/ipf/ipf.rules.
+
+ IP Filter has two sets of rules, the active set and the
+inactive set. By default, all operations are performed on
+
+
+
+
+
+
+
+
+
+ -30-
+
+
+the active set. You can manipulate the inactive set by
+adding -I to the ipf command line. The two sets can be
+toggled by using the -s command line option. This is very
+useful for testing new rule sets without wiping out the old
+rule set.
+
+ Rules can also be removed from the list instead of
+added by using the -r command line option, but it is gener-
+ally a safer idea to flush the rule set that you're working
+on with -F and completely reload it when making changes.
+
+ In summary, the easiest way to load a rule set is ipf
+-Fa -f /etc/ipf.rules. For more complicated manipulations
+of the rule set, please see the ipf(1) man page.
+
+6. Loading and Manipulating NAT Rules; The ipnat Utility
+
+ NAT rules are loaded by using the ipnat utility. The
+NAT rules can be stored in any file on the system, but typi-
+cally these rules are stored in /etc/ipnat.rules,
+/usr/local/etc/ipnat.rules, or /etc/opt/ipf/ipnat.rules.
+
+ Rules can also be removed from the list instead of
+added by using the -r command line option, but it is gener-
+ally a safer idea to flush the rule set that you're working
+on with -C and completely reload it when making changes.
+Any active mappings are not affected by -C, and can be
+removed with -F.
+
+ NAT rules and active mappings can be examined with the
+-l command line option.
+
+ In summary, the easiest way to load a NAT rule set is
+ipnat -CF -f /etc/ipnat.rules.
+
+7. Monitoring and Debugging
+
+ There will come a time when you are interested in what
+your firewall is actually doing, and ipfilter would be
+incomplete if it didn't have a full suite of status monitor-
+ing tools.
+
+7.1. The ipfstat utility
+
+ In its simplest form, ipfstat displays a table of
+interesting data about how your firewall is performing, such
+as how many packets have been passed or blocked, if they
+were logged or not, how many state entries have been made,
+and so on. Here's an example of something you might see
+from running the tool:
+
+ # ipfstat
+ input packets: blocked 99286 passed 1255609 nomatch 14686 counted 0
+ output packets: blocked 4200 passed 1284345 nomatch 14687 counted 0
+
+
+
+
+
+
+
+
+
+ -31-
+
+
+ input packets logged: blocked 99286 passed 0
+ output packets logged: blocked 0 passed 0
+ packets logged: input 0 output 0
+ log failures: input 3898 output 0
+ fragment state(in): kept 0 lost 0
+ fragment state(out): kept 0 lost 0
+ packet state(in): kept 169364 lost 0
+ packet state(out): kept 431395 lost 0
+ ICMP replies: 0 TCP RSTs sent: 0
+ Result cache hits(in): 1215208 (out): 1098963
+ IN Pullups succeeded: 2 failed: 0
+ OUT Pullups succeeded: 0 failed: 0
+ Fastroute successes: 0 failures: 0
+ TCP cksum fails(in): 0 (out): 0
+ Packet log flags set: (0)
+ none
+
+ipfstat is also capable of showing you your current rule
+list. Using the -i or the -o flag will show the currently
+loaded rules for in or out, respectively. Adding a -h to
+this will provide more useful information at the same time
+by showing you a "hit count" on each rule. For example:
+
+ # ipfstat -ho
+ 2451423 pass out on xl0 from any to any
+ 354727 block out on ppp0 from any to any
+ 430918 pass out quick on ppp0 proto tcp/udp from 20.20.20.0/24 to any keep state keep frags
+
+From this, we can see that perhaps there's something abnor-
+mal going on, since we've got a lot of blocked packets out-
+bound, even with a very permissive pass out rule. Something
+here may warrant further investigation, or it may be func-
+tioning perfectly by design. ipfstat can't tell you if your
+rules are right or wrong, it can only tell you what is hap-
+pening because of your rules.
+
+To further debug your rules, you may want to use the -n
+flag, which will show the rule number next to each rule.
+
+ # ipfstat -on
+ @1 pass out on xl0 from any to any
+ @2 block out on ppp0 from any to any
+ @3 pass out quick on ppp0 proto tcp/udp from 20.20.20.0/24 to any keep state keep frags
+
+The final piece of really interesting information that ipfs-
+tat can provide us is a dump of the state table. This is
+done with the -s flag:
+
+ # ipfstat -s
+ 281458 TCP
+ 319349 UDP
+ 0 ICMP
+ 19780145 hits
+ 5723648 misses
+
+
+
+
+
+
+
+
+
+ -32-
+
+
+ 0 maximum
+ 0 no memory
+ 1 active
+ 319349 expired
+ 281419 closed
+ 100.100.100.1 -> 20.20.20.1 ttl 864000 pass 20490 pr 6 state 4/4
+ pkts 196 bytes 17394 987 -> 22 585538471:2213225493 16592:16500
+ pass in log quick keep state
+ pkt_flags & b = 2, pkt_options & ffffffff = 0
+ pkt_security & ffff = 0, pkt_auth & ffff = 0
+
+Here we see that we have one state entry for a TCP connec-
+tion. The output will vary slightly from version to ver-
+sion, but the basic information is the same. We can see in
+this connection that we have a fully established connection
+(represented by the 4/4 state. Other states are incomplete
+and will be documented fully later.) We can see that the
+state entry has a time to live of 240 hours, which is an
+absurdly long time, but is the default for an established
+TCP connection. This TTL counter is decremented every sec-
+ond that the state entry is not used, and will finally
+result in the connection being purged if it has been left
+idle. The TTL is also reset to 864000 whenever the state
+IS used, ensuring that the entry will not time out while it
+is being actively used. We can also see that we have passed
+196 packets consisting of about 17kB worth of data over this
+connection. We can see the ports for both endpoints, in
+this case 987 and 22; which means that this state entry rep-
+resents a connection from 100.100.100.1 port 987 to
+20.20.20.1 port 22. The really big numbers in the second
+line are the TCP sequence numbers for this connection, which
+helps to ensure that someone isn't easily able to inject a
+forged packet into your session. The TCP window is also
+shown. The third line is a synopsis of the implicit rule
+that was generated by the keep state code, showing that this
+connection is an inbound connection.
+
+7.2. The ipmon utility
+
+ ipfstat is great for collecting snapshots of what's
+going on on the system, but it's often handy to have some
+kind of log to look at and watch events as they happen in
+time. ipmon is this tool. ipmon is capable of watching
+the packet log (as created with the log keyword in your
+rules), the state log, or the nat log, or any combination of
+the three. This tool can either be run in the foreground,
+or as a daemon which logs to syslog or a file. If we wanted
+to watch the state table in action, ipmon -o S would show
+this:
+
+ # ipmon -o S
+ 01/08/1999 15:58:57.836053 STATE:NEW 100.100.100.1,53 -> 20.20.20.15,53 PR udp
+ 01/08/1999 15:58:58.030815 STATE:NEW 20.20.20.15,123 -> 128.167.1.69,123 PR udp
+ 01/08/1999 15:59:18.032174 STATE:NEW 20.20.20.15,123 -> 128.173.14.71,123 PR udp
+
+
+
+
+
+
+
+
+
+ -33-
+
+
+ 01/08/1999 15:59:24.570107 STATE:EXPIRE 100.100.100.1,53 -> 20.20.20.15,53 PR udp Pkts 4 Bytes 356
+ 01/08/1999 16:03:51.754867 STATE:NEW 20.20.20.13,1019 -> 100.100.100.10,22 PR tcp
+ 01/08/1999 16:04:03.070127 STATE:EXPIRE 20.20.20.13,1019 -> 100.100.100.10,22 PR tcp Pkts 63 Bytes 4604
+
+Here we see a state entry for an external dns request off
+our nameserver, two xntp pings to well-known time servers,
+and a very short lived outbound ssh connection.
+
+ ipmon is also capable of showing us what packets have
+been logged. For example, when using state, you'll often
+run into packets like this:
+
+ # ipmon -o I
+ 15:57:33.803147 ppp0 @0:2 b 100.100.100.103,443 -> 20.20.20.10,4923 PR tcp len 20 1488 -A
+
+What does this mean? The first field is obvious, it's a
+timestamp. The second field is also pretty obvious, it's
+the interface that this event happened on. The third field
+@0:2 is something most people miss. This is the rule that
+caused the event to happen. Remember ipfstat -in? If you
+wanted to know where this came from, you could look there
+for rule 2 in rule group 0. The fourth field, the little
+"b" says that this packet was blocked, and you'll generally
+ignore this unless you're logging passed packets as well,
+which would be a little "p" instead. The fifth and sixth
+fields are pretty self-explanatory, they say where this
+packet came from and where it was going. The seventh ("PR")
+and eighth fields tell you the protocol and the ninth field
+tells you the size of the packet. The last part, the "-A"
+in this case, tells you the flags that were on the packet;
+This one was an ACK packet. Why did I mention state ear-
+lier? Due to the often laggy nature of the Internet, some-
+times packets will be regenerated. Sometimes, you'll get
+two copies of the same packet, and your state rule which
+keeps track of sequence numbers will have already seen this
+packet, so it will assume that the packet is part of a dif-
+ferent connection. Eventually this packet will run into a
+real rule and have to be dealt with. You'll often see the
+last packet of a session being closed get logged because the
+keep state code has already torn down the connection before
+the last packet has had a chance to make it to your fire-
+wall. This is normal, do not be alarmed. Another example
+packet that might be logged:
+
+ 12:46:12.470951 xl0 @0:1 S 20.20.20.254 -> 255.255.255.255 PR icmp len 20 9216 icmp 9/0
+
+-----------
+ For a technical presentation of the IP Filter
+stateful inspection engine, please see the white
+paper Real Stateful TCP Packet Filtering in IP
+Filter, by Guido van Rooij. This paper may be
+found at
+<http://www.iae.nl/users/guido/papers/tcp_filter-
+ing.ps.gz>
+
+
+
+
+
+
+
+
+
+ -34-
+
+
+This is an ICMP router discovery broadcast. We can tell by
+the ICMP type 9/0.
+
+Finally, ipmon also lets us look at the NAT table in action.
+
+ # ipmon -o N
+ 01/08/1999 05:30:02.466114 @2 NAT:RDR 20.20.20.253,113 <- -> 20.20.20.253,113 [100.100.100.13,45816]
+ 01/08/1999 05:30:31.990037 @2 NAT:EXPIRE 20.20.20.253,113 <- -> 20.20.20.253,113 [100.100.100.13,45816] Pkts 10 Bytes 455
+
+This would be a redirection to an identd that lies to pro-
+vide ident service for the hosts behind our NAT, since they
+are typically unable to provide this service for themselves
+with ordinary natting.
+
+
+
+
+8. Specific Applications of IP Filter - Things that don't
+fit, but should be mentioned anyway.
+
+8.1. Keep State With Servers and Flags.
+
+ Keeping state is a good thing, but it's quite easy to
+make a mistake in the direction that you want to keep state
+in. Generally, you want to have a keep state keyword on
+the first rule that interacts with a packet for the connec-
+tion. One common mistake that is made when mixing state
+tracking with filtering on flags is this:
+
+ block in all
+ pass in quick proto tcp from any to 20.20.20.20/32 port = 23 flags S
+ pass out all keep state
+
+That certainly appears to allow a connection to be created
+to the telnet server on 20.20.20.20, and the replies to go
+back. If you try using this rule, you'll see that it does
+work--Momentarily. Since we're filtering for the SYN flag,
+the state entry never fully gets completed, and the default
+time to live for an incomplete state is 60 seconds.
+
+We can solve this by rewriting the rules in one of two ways:
+
+1)
+
+ block in all
+ pass in quick proto tcp from any to 20.20.20.20/32 port = 23 keep state
+ block out all
+
+or:
+
+2)
+
+ block in all
+ pass in quick proto tcp from any to 20.20.20.20/32 port = 23 flags S keep state
+
+
+
+
+
+
+
+
+
+ -35-
+
+
+ pass out all keep state
+
+Either of these sets of rules will result in a fully estab-
+lished state entry for a connection to your server.
+
+8.2. Coping With FTP
+
+ FTP is one of those protocols that you just have to sit
+back and ask "What the heck were they thinking?" FTP has
+many problems that the firewall administrator needs to deal
+with. What's worse, the problems the administrator must
+face are different between making ftp clients work and mak-
+ing ftp servers work.
+
+ Within the FTP protocol, there are two forms of data
+transfer, called active and passive. Active transfers are
+those where the server connects to an open port on the
+client to send data. Conversely, passive transfers are
+those where the client connects to the server to receive
+data.
+
+8.2.1. Running an FTP Server
+
+ In running an FTP server, handling Active FTP sessions
+is easy to setup. At the same time, handling Passive FTP
+sessions is a big problem. First we'll cover how to handle
+Active FTP, then move on to Passive. Generally, we can han-
+dle Active FTP sessions like we would an incoming HTTP or
+SMTP connection; just open the ftp port and let keep state
+do the rest:
+
+ pass in quick proto tcp from any to 20.20.20.20/32 port = 21 flags S keep state
+ pass out proto tcp all keep state
+
+These rules will allow Active FTP sessions, the most common
+type, to your ftp server on 20.20.20.20.
+
+ The next challenge becomes handling Passive FTP connec-
+tions. Web browsers default to this mode, so it's becoming
+quite popular and as such it should be supported. The prob-
+lem with passive connections are that for every passive con-
+nection, the server starts listening on a new port (usually
+above 1023). This is essentially like creating a new
+unknown service on the server. Assuming we have a good
+firewall with a default-deny policy, that new service will
+be blocked, and thus Active FTP sessions are broken. Don't
+despair! There's hope yet to be had.
+
+ A person's first inclination to solving this problem
+might be to just open up all ports above 1023. In truth,
+this will work:
+
+ pass in quick proto tcp from any to 20.20.20.20/32 port > 1023 flags S keep state
+ pass out proto tcp all keep state
+
+
+
+
+
+
+
+
+
+ -36-
+
+
+This is somewhat unsatisfactory, though. By letting every-
+thing above 1023 in, we actually open ourselves up for a
+number of potential problems. While 1-1023 is the desig-
+nated area for server services to run, numerous programs
+decided to use numbers higher than 1023, such as nfsd and X.
+
+ The good news is that your FTP server gets to decide
+which ports get assigned to passive sessions. This means
+that instead of opening all ports above 1023, you can allo-
+cate ports 15001-19999 as ftp ports and only open that range
+of your firewall up. In wu-ftpd, this is done with the pas-
+sive ports option in ftpaccess. Please see the man page on
+ftpaccess for details in wu-ftpd configuration. On the
+ipfilter side, all we need do is setup corresponding rules:
+
+ pass in quick proto tcp from any to 20.20.20.20/32 port 15000 >< 20000 flags S keep state
+ pass out proto tcp all keep state
+
+If even this solution doesn't satisfy you, you can always
+hack IPF support into your FTP server, or FTP server support
+into IPF.
+
+8.2.2. Running an FTP Client
+
+ While FTP server support is still less than perfect in
+IPF, FTP client support has been working well since 3.3.3.
+As with FTP servers, there are two types of ftp client
+transfers: passive and active.
+
+ The simplest type of client transfer from the fire-
+wall's standpoint is the passive transfer. Assuming you're
+keeping state on all outbound tcp sessions, passive trans-
+fers will work already. If you're not doing this already,
+please consider the following:
+
+ pass out proto tcp all keep state
+
+The second type of client transfer, active, is a bit more
+troublesome, but nonetheless a solved problem. Active
+transfers cause the server to open up a second connection
+back to the client for data to flow through. This is nor-
+mally a problem when there's a firewall in the middle, stop-
+ping outside connections from coming back in. To solve
+this, ipfilter includes an ipnat proxy which temporarily
+opens up a hole in the firewall just for the FTP server to
+get back to the client. Even if you're not using ipnat to
+do nat, the proxy is still effective. The following rules
+is the bare minimum to add to the ipnat configuration file
+(ep0 should be the interface name of the outbound network
+connection):
+
+ map ep0 0/0 -> 0/32 proxy port 21 ftp/tcp
+
+
+
+
+
+
+
+
+
+
+
+ -37-
+
+
+For more details on ipfilter's internal proxies, see section
+3.6
+
+8.3. Assorted Kernel Variables
+
+ There are some useful kernel tunes that either need to
+be set for ipf to function, or are just generally handy to
+know about for building firewalls. The first major one you
+must set is to enable IP Forwarding, otherwise ipf will do
+very little, as the underlying ip stack won't actually route
+packets.
+
+IP Forwarding:
+
+openbsd:
+ net.inet.ip.forwarding=1
+
+
+freebsd:
+ net.inet.ip.forwarding=1
+
+
+netbsd:
+ net.inet.ip.forwarding=1
+
+
+solaris:
+ ndd -set /dev/ip ip_forwarding 1
+
+Ephemeral Port Adjustment:
+
+openbsd:
+ net.inet.ip.portfirst = 25000
+
+
+freebsd:
+ net.inet.ip.portrange.first = 25000 net.inet.ip.por-
+ trange.last = 49151
+
+
+netbsd:
+ net.inet.ip.anonportmin = 25000 net.inet.ip.anonportmax
+ = 49151
+
+
+solaris:
+ ndd -set /dev/tcp tcp_smallest_anon_port 25000
+ ndd -set /dev/tcp tcp_largest_anon_port 65535
+
+Other Useful Values:
+
+openbsd:
+ net.inet.ip.sourceroute = 0
+ net.inet.ip.directed-broadcast = 0
+
+
+
+
+
+
+
+
+
+ -38-
+
+
+freebsd:
+ net.inet.ip.sourceroute=0
+ net.ip.accept_sourceroute=0
+
+
+netbsd:
+ net.inet.ip.allowsrcrt=0
+ net.inet.ip.forwsrcrt=0
+ net.inet.ip.directed-broadcast=0
+ net.inet.ip.redirect=0
+
+
+solaris:
+ ndd -set /dev/ip ip_forward_directed_broadcasts 0
+ ndd -set /dev/ip ip_forward_src_routed 0
+ ndd -set /dev/ip ip_respond_to_echo_broadcast 0
+
+In addition, freebsd has some ipf specific sysctl variables.
+
+ net.inet.ipf.fr_flags: 0
+ net.inet.ipf.fr_pass: 514
+ net.inet.ipf.fr_active: 0
+ net.inet.ipf.fr_tcpidletimeout: 864000
+ net.inet.ipf.fr_tcpclosewait: 60
+ net.inet.ipf.fr_tcplastack: 20
+ net.inet.ipf.fr_tcptimeout: 120
+ net.inet.ipf.fr_tcpclosed: 1
+ net.inet.ipf.fr_udptimeout: 120
+ net.inet.ipf.fr_icmptimeout: 120
+ net.inet.ipf.fr_defnatage: 1200
+ net.inet.ipf.fr_ipfrttl: 120
+ net.inet.ipf.ipl_unreach: 13
+ net.inet.ipf.ipl_inited: 1
+ net.inet.ipf.fr_authsize: 32
+ net.inet.ipf.fr_authused: 0
+ net.inet.ipf.fr_defaultauthage: 600
+
+
+
+
+9. Fun with ipf!
+
+ This section doesn't necessarily teach you anything new
+about ipf, but it may raise an issue or two that you haven't
+yet thought up on your own, or tickle your brain in a way
+that you invent something interesting that we haven't
+thought of.
+
+9.1. Localhost Filtering
+
+ A long time ago at a university far, far away, Wietse
+Venema created the tcp-wrapper package, and ever since, it's
+been used to add a layer of protection to network services
+all over the world. This is good. But, tcp-wrappers have
+
+
+
+
+
+
+
+
+
+ -39-
+
+
+flaws. For starters, they only protect TCP services, as the
+name suggests. Also, unless you run your service from
+inetd, or you have specifically compiled it with libwrap and
+the appropriate hooks, your service isn't protected. This
+leaves gigantic holes in your host security. We can plug
+these up by using ipf on the local host. For example, my
+laptop often gets plugged into or dialed into networks that
+I don't specifically trust, and so, I use the following rule
+set:
+
+ pass in quick on lo0 all
+ pass out quick on lo0 all
+
+ block in log all
+ block out all
+
+ pass in quick proto tcp from any to any port = 113 flags S keep state
+ pass in quick proto tcp from any to any port = 22 flags S keep state
+ pass in quick proto tcp from any port = 20 to any port 39999 >< 45000 flags S keep state
+
+ pass out quick proto icmp from any to any keep state
+ pass out quick proto tcp/udp from any to any keep state keep frags
+
+It's been like that for quite a while, and I haven't suf-
+fered any pain or anguish as a result of having ipf loaded
+up all the time. If I wanted to tighten it up more, I could
+switch to using the NAT ftp proxy and I could add in some
+rules to prevent spoofing. But even as it stands now, this
+box is far more restrictive about what it presents to the
+local network and beyond than the typical host does. This
+is a good thing if you happen to run a machine that allows a
+lot of users on it, and you want to make sure one of them
+doesn't happen to start up a service they wern't supposed
+to. It won't stop a malicious hacker with root access from
+adjusting your ipf rules and starting a service anyway, but
+it will keep the "honest" folks honest, and your weird ser-
+vices safe, cozy and warm even on a malicious LAN. A big
+win, in my opinion. Using local host filtering in addition
+to a somewhat less-restrictive "main firewall" machine can
+solve many performance issues as well as political night-
+mares like "Why doesn't ICQ work?" and "Why can't I put a
+web server on my own workstation! It's MY WORKSTATION!!"
+Another very big win. Who says you can't have security and
+convienence at the same time?
+
+9.2. What Firewall? Transparent filtering.
+
+ One major concern in setting up a firewall is the
+integrity of the firewall itself. Can somebody break into
+your firewall, thereby subverting its ruleset? This is a
+common problem administrators must face, particularly when
+they're using firewall solutions on top of their Unix/NT
+machines. Some use it as an argument for blackbox hardware
+solutions, under the flawed notion that inherent obscurity
+
+
+
+
+
+
+
+
+
+ -40-
+
+
+of their closed system increases their security. We have a
+better way.
+
+ Many network admins are familiar with the common ether-
+net bridge. This is a device that connects two separate
+ethernet segments to make them one. An ethernet bridge is
+typically used to connect separate buildings, switch network
+speeds, and extend maximum wire lengths. Hubs and switches
+are common bridges, sometimes they're just 2 ported devices
+called repeaters. Recent versions of Linux, OpenBSD,
+NetBSD, and FreeBSD include code to convert $1000 PCs into
+$10 bridges, too! What all bridges tend to have in common
+is that though they sit in the middle of a connection
+between two machines, the two machines don't know the bridge
+is there. Enter ipfilter and OpenBSD.
+
+ Ethernet bridging takes place at Layer2 on the ISO
+stack. IP takes place on Layer3. IP Filter in primarily
+concerned with Layer3, but dabbles in Layer2 by working with
+interfaces. By mixing IP filter with OpenBSD's bridge
+device, we can create a firewall that is both invisible and
+unreachable. The system needs no IP address, it doesn't
+even need to reveal its ethernet address. The only telltale
+sign that the filter might be there is that latency is some-
+what higher than a piece of cat5 would normally make it, and
+that packets don't seem to make it to their final destina-
+tion.
+
+ The setup for this sort of ruleset is surprisingly sim-
+ple, too. In OpenBSD, the first bridge device is named
+bridge0. Say we have two ethernet cards in our machine as
+well, xl0 and xl1. To turn this machine into a bridge, all
+one need do is enter the following three commands:
+
+ brconfig bridge0 add xl0 add xl1 up
+ ifconfig xl0 up
+ ifconfig xl1 up
+
+At ths point, all traffic ariving on xl0 is sent out xl1 and
+all traffic on xl1 is sent out xl0. You'll note that nei-
+ther interface has been assigned an IP address, nor do we
+need assign one. All things considered, it's likely best we
+not add one at all.
+
+ Rulesets behave essentially the as the always have.
+Though there is a bridge0 interface, we don't filter based
+on it. Rules continue to be based upon the particular
+interface we're using, making it important which network
+cable is plugged into which network card in the back of the
+machine. Let's start with some basic filtering to illis-
+trate what's happened. Assume the network used to look like
+this:
+
+
+
+
+
+
+
+
+
+
+
+ -41-
+
+
+ 20.20.20.1 <---------------------------------> 20.20.20.0/24 network hub
+
+That is, we have a router at 20.20.20.1 connected to the
+20.20.20.0/24 network. All packets from the 20.20.20.0/24
+network go through 20.20.20.1 to get to the outside world
+and vice versa. Now we add the Ipf Bridge:
+
+ 20.20.20.1 <-------/xl0 IpfBridge xl1/-------> 20.20.20.0/24 network hub
+
+We also have the following ruleset loaded on the IpfBridge
+host:
+
+ pass in quick all
+ pass out quick all
+
+With this ruleset loaded, the network is functionally iden-
+tical. As far as the 20.20.20.1 router is concerned, and as
+far as the 20.20.20.0/24 hosts are concerned, the two net-
+work diagrams are identical. Now let's change the ruleset
+some:
+
+ block in quick on xl0 proto icmp
+ pass in quick all
+ pass out quick all
+
+Still, 20.20.20.1 and 20.20.20.0/24 think the network is
+identical, but if 20.20.20.1 attempts to ping 20.20.20.2, it
+will never get a reply. What's more, 20.20.20.2 won't even
+get the packet in the first place. IPfilter will intercept
+the packet before it even gets to the other end of the vir-
+tual wire. We can put a bridged filter anywhere. Using
+this method we can shrink the network trust circle down an
+individual host level (given enough ethernet cards:-)
+
+ Blocking icmp from the world seems kind of silly, espe-
+cially if you're a sysadmin and like pinging the world, to
+traceroute, or to resize your MTU. Let's construct a better
+ruleset and take advantage of the original key feature of
+ipf: stateful inspection.
+
+ pass in quick on xl1 proto tcp keep state
+ pass in quick on xl1 proto udp keep state
+ pass in quick on xl1 proto icmp keep state
+ block in quick on xl0
+
+In this situation, the 20.20.20.0/24 network (perhaps more
+aptly called the xl1 network) can now reach the outside
+world, but the outside world can't reach it, and it can't
+figure out why, either. The router is accessible, the hosts
+are active, but the outside world just can't get in. Even
+if the router itself were compromised, the firewall would
+still be active and successful.
+
+
+
+
+
+
+
+
+
+
+
+ -42-
+
+
+ So far, we've been filtering by interface and protocol
+only. Even though bridging is concerned layer2, we can
+still discriminate based on IP address. Normally we have a
+few services running, so our ruleset may look like this:
+
+ pass in quick on xl1 proto tcp keep state
+ pass in quick on xl1 proto udp keep state
+ pass in quick on xl1 proto icmp keep state
+ block in quick on xl1 # nuh-uh, we're only passing tcp/udp/icmp sir.
+ pass in quick on xl0 proto udp from any to 20.20.20.2/32 port=53 keep state
+ pass in quick on xl0 proto tcp from any to 20.20.20.2/32 port=53 flags S keep state
+ pass in quick on xl0 proto tcp from any to 20.20.20.3/32 port=25 flags S keep state
+ pass in quick on xl0 proto tcp from any to 20.20.20.7/32 port=80 flags S keep state
+ block in quick on xl0
+
+Now we have a network where 20.20.20.2 is a zone serving
+name server, 20.20.20.3 is an incoming mail server, and
+20.20.20.7 is a web server.
+
+ Bridged IP Filter is not yet perfect, we must confess.
+
+ First, You'll note that all the rules are setup using
+the in direction instead of a combination of in and out.
+This is because the out direction is presently unimplemented
+with bridging in OpenBSD. This was originally done to pre-
+vent vast performance drops using multiple interfaces. Work
+has been done in speeding it up, but it remains unimple-
+mented. If you really want this feature, you might try your
+hand at working on the code or asking the OpenBSD people how
+you can help.
+
+ Second, using IP Filter with bridging makes the use of
+IPF's NAT features inadvisable, if not downright dangerous.
+The first problem is that it would give away that there's a
+filtering bridge. The second problem would be that the
+bridge has no IP address to masquerade with, which will most
+assuredly lead to confusion and perhaps a kernel panic to
+boot. You can, of course, put an IP address on the outbound
+interface to make NAT work, but part of the glee of bridging
+is thus diminished.
+
+9.2.1. Using Transparent Filtering to Fix Network Design
+Mistakes
+
+ Many organizations started using IP well before they
+thought a firewall or a subnet would be a good idea. Now
+they have class-C sized networks or larger that include all
+their servers, their workstations, their routers, coffee
+makers, everything. The horror! Renumbering with proper
+subnets, trust levels, filters, and so are in both time con-
+suming and expensive. The expense in hardware and man hours
+alone is enough to make most organizations unwilling to
+really solve the problem, not to mention the downtime
+involved. The typical problem network looks like this:
+
+
+
+
+
+
+
+
+
+ -43-
+
+
+ 20.20.20.1 router 20.20.20.6 unix server
+ 20.20.20.2 unix server 20.20.20.7 nt workstation
+ 20.20.20.3 unix server 20.20.20.8 nt server
+ 20.20.20.4 win98 workstation 20.20.20.9 unix workstation
+ 20.20.20.5 intelligent switch 20.20.20.10 win95 workstation
+
+Only it's about 20 times larger and messier and frequently
+undocumented. Ideally, you'd have all the trusting servers
+in one subnet, all the work- stations in another, and the
+network switches in a third. Then the router would filter
+packets between the subnets, giving the workstations limited
+access to the servers, nothing access to the switches, and
+only the sysadmin's workstation access to the coffee pot.
+I've never seen a class-C sized network with such coherence.
+IP Filter can help.
+
+ To start with, we're going to separate the router, the
+workstations, and the servers. To do this we're going to
+need 2 hubs (or switches) which we probably already have,
+and an IPF machine with 3 ethernet cards. We're going to
+put all the servers on one hub and all the workstations on
+the other. Normally we'd then connect the hubs to each
+other, then to the router. Instead, we're going to plug the
+router into IPF's xl0 interface, the servers into IPF's xl1
+interface, and the workstations into IPF's xl2 interface.
+Our network diagram looks something like this:
+
+ | 20.20.20.2 unix server
+ router (20.20.20.1) ____________| 20.20.20.3 unix server
+ | / | 20.20.20.6 unix server
+ | /xl1 | 20.20.20.7 nt server
+ ------------/xl0 IPF Bridge <
+ xl2 | 20.20.20.4 win98 workstation
+ ____________| 20.20.20.8 nt workstation
+ | 20.20.20.9 unix workstation
+ | 20.20.20.10 win95 workstation
+
+Where once there was nothing but interconnecting wires, now
+there's a filtering bridge that not a single host needs to
+be modified to take advantage of. Presumably we've already
+enabled bridging so the network is behaving perfectly nor-
+mally. Further, we're starting off with a ruleset much like
+our last ruleset:
+
+ pass in quick on xl0 proto udp from any to 20.20.20.2/32 port=53 keep state
+ pass in quick on xl0 proto tcp from any to 20.20.20.2/32 port=53 flags S keep state
+ pass in quick on xl0 proto tcp from any to 20.20.20.3/32 port=25 flags S keep state
+ pass in quick on xl0 proto tcp from any to 20.20.20.7/32 port=80 flags S keep state
+ block in quick on xl0
+ pass in quick on xl1 proto tcp keep state
+ pass in quick on xl1 proto udp keep state
+ pass in quick on xl1 proto icmp keep state
+ block in quick on xl1 # nuh-uh, we're only passing tcp/udp/icmp sir.
+ pass in quick on xl2 proto tcp keep state
+
+
+
+
+
+
+
+
+
+ -44-
+
+
+ pass in quick on xl2 proto udp keep state
+ pass in quick on xl2 proto icmp keep state
+ block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir.
+
+Once again, traffic coming from the router is restricted to
+DNS, SMTP, and HTTP. At the moment, the servers and the
+workstations can exchange traffic freely. Depending on what
+kind of organization you are, there might be something about
+this network dynamic you don't like. Perhaps you don't want
+your workstations getting access to your servers at all?
+Take the xl2 ruleset of:
+
+ pass in quick on xl2 proto tcp keep state
+ pass in quick on xl2 proto udp keep state
+ pass in quick on xl2 proto icmp keep state
+ block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir.
+
+And change it to:
+
+ block in quick on xl2 from any to 20.20.20.0/24
+ pass in quick on xl2 proto tcp keep state
+ pass in quick on xl2 proto udp keep state
+ pass in quick on xl2 proto icmp keep state
+ block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir.
+
+Perhaps you want them to just get to the servers to get and
+send their mail with IMAP? Easily done:
+
+ pass in quick on xl2 proto tcp from any to 20.20.20.3/32 port=25
+ pass in quick on xl2 proto tcp from any to 20.20.20.3/32 port=143
+ block in quick on xl2 from any to 20.20.20.0/24
+ pass in quick on xl2 proto tcp keep state
+ pass in quick on xl2 proto udp keep state
+ pass in quick on xl2 proto icmp keep state
+ block in quick on xl2 # nuh-uh, we're only passing tcp/udp/icmp sir.
+
+Now your workstations and servers are protected from the
+outside world, and the servers are protected from your work-
+stations.
+
+ Perhaps the opposite is true, maybe you want your work-
+stations to be able to get to the servers, but not the out-
+side world. After all, the next generation of exploits is
+breaking the clients, not the servers. In this case, you'd
+change the xl2 rules to look more like this:
+
+ pass in quick on xl2 from any to 20.20.20.0/24
+ block in quick on xl2
+
+Now the servers have free reign, but the clients can only
+connect to the servers. We might want to batten down the
+hatches on the servers, too:
+
+ pass in quick on xl1 from any to 20.20.20.0/24
+
+
+
+
+
+
+
+
+
+ -45-
+
+
+ block in quick on xl1
+
+With the combination of these two, the clients and servers
+can talk to each other, but neither can access the outside
+world (though the outside world can get to the few services
+from earlier). The whole ruleset would look something like
+this:
+
+ pass in quick on xl0 proto udp from any to 20.20.20.2/32 port=53 keep state
+ pass in quick on xl0 proto tcp from any to 20.20.20.2/32 port=53 flags S keep state
+ pass in quick on xl0 proto tcp from any to 20.20.20.3/32 port=25 flags S keep state
+ pass in quick on xl0 proto tcp from any to 20.20.20.7/32 port=80 flags S keep state
+ block in quick on xl0
+ pass in quick on xl1 from any to 20.20.20.0/24
+ block in quick on xl1
+ pass in quick on xl2 from any to 20.20.20.0/24
+ block in quick on xl2
+
+So remember, when your network is a mess of twisty IP
+addresses and machine classes, transparent filtered bridges
+can solve a problem that would otherwise be lived with and
+perhaps someday exploited.
+
+9.3. Drop-Safe Logging With dup-to and to.
+
+ Until now, we've been using the filter to drop packets.
+Instead of dropping them, let's consider passing them on to
+another system that can do something useful with this infor-
+mation beyond the logging we can perform with ipmon. Our
+firewall system, be it a bridge or a router, can have as
+many interfaces as we can cram into the system. We can use
+this information to create a "drop-safe" for our packets. A
+good example of a use for this would be to implement an
+intrusion detection network. For starters, it might be
+desirable to hide the presence of our intrusion detection
+systems from our real network so that we can keep them from
+being detected.
+
+ Before we get started, there are some operational char-
+acteristics that we need to make note of. If we are only
+going to deal with blocked packets, we can use either the to
+keyword or the fastroute keyword. (We'll cover the differ-
+ences between these two later) If we're going to pass the
+packets like we normally would, we need to make a copy of
+the packet for our drop-safe log with the dup-to keyword.
+
+9.3.1. The dup-to Method
+
+ If, for example, we wanted to send a copy of everything
+going out the xl3 interface off to our drop-safe network on
+ed0, we would use this rule in our filter list:
+
+ pass out on xl3 dup-to ed0 from any to any
+
+
+
+
+
+
+
+
+
+
+ -46-
+
+
+You might also have a need to send the packet directly to a
+specific IP address on your drop-safe network instead of
+just making a copy of the packet out there and hoping for
+the best. To do this, we modify our rule slightly:
+
+ pass out on xl3 dup-to ed0:192.168.254.2 from any to any
+
+But be warned that this method will alter the copied
+packet's destination address, and may thus destroy the use-
+fulness of the log. For this reason, we recommend only
+using the known address method of logging when you can be
+certain that the address that you're logging to corresponds
+in some way to what you're logging for (e.g.: don't use
+"192.168.254.2" for logging for both your web server and
+your mail server, since you'll have a hard time later trying
+to figure out which system was the target of a specific set
+of packets.)
+
+ This technique can be used quite effectively if you
+treat an IP Address on your drop-safe network in much the
+same way that you would treat a Multicast Group on the real
+internet. (e.g.: "192.168.254.2" could be the channel for
+your http traffic analysis system, "23.23.23.23" could be
+your channel for telnet sessions, and so on.) You don't
+even need to actually have this address set as an address or
+alias on any of your analysis systems. Normally, your
+ipfilter machine would need to ARP for the new destination
+address (using dup-to ed0:192.168.254.2 style, of course)
+but we can avoid that issue by creating a static arp entry
+for this "channel" on our ipfilter system.
+
+ In general, though, dup-to ed0 is all that is required
+to get a new copy of the packet over to our drop-safe net-
+work for logging and examination.
+
+9.3.2. The to Method
+
+ The dup-to method does have an immediate drawback,
+though. Since it has to make a copy of the packet and
+optionally modify it for its new destination, it's going to
+take a while to complete all this work and be ready to deal
+with the next packet coming in to the ipfilter system.
+
+ If we don't care about passing the packet to its normal
+destination and we were going to block it anyway, we can
+just use the to keyword to push this packet past the normal
+routing table and force it to go out a different interface
+than it would normally go out.
+
+ block in quick on xl0 to ed0 proto tcp from any to any port < 1024
+
+we use block quick for to interface routing, because like
+fastroute, the to interface code will generate two packet
+paths through ipfilter when used with pass, and likely cause
+
+
+
+
+
+
+
+
+
+ -47-
+
+
+your system to panic.
+
+
+
+10. Bogus Network Filtering, the ultimate in current anti-
+spoofing technology.
+
+ We've spent a little bit of time tracking down the cur-
+rent vast tracts of IP address space that have been reserved
+by the IANA for various reasons, or are otherwise not cur-
+rently in use at the time this document was written. Since
+none of these address ranges should be in use currently,
+there should be no legitimate reason to ever see them as a
+source address, or to send them traffic as a destination
+address, right? Right!
+
+ So without further ado, the complete list of bogus net-
+works:
+
+ #
+ # s/OUTSIDE/outside-interface (eg: fxp0)
+ # s/MYNET/network-cidr-address (eg: 1.2.3.0/24)
+ #
+ block in on OUTSIDE all
+ block in quick on OUTSIDE from 0.0.0.0/7 to any
+ block in quick on OUTSIDE from 2.0.0.0/8 to any
+ block in quick on OUTSIDE from 5.0.0.0/8 to any
+ block in quick on OUTSIDE from 10.0.0.0/8 to any
+ block in quick on OUTSIDE from 23.0.0.0/8 to any
+ block in quick on OUTSIDE from 27.0.0.0/8 to any
+ block in quick on OUTSIDE from 31.0.0.0/8 to any
+ block in quick on OUTSIDE from 67.0.0.0/8 to any
+ block in quick on OUTSIDE from 68.0.0.0/6 to any
+ block in quick on OUTSIDE from 72.0.0.0/5 to any
+ block in quick on OUTSIDE from 80.0.0.0/4 to any
+ block in quick on OUTSIDE from 96.0.0.0/3 to any
+ block in quick on OUTSIDE from 127.0.0.0/8 to any
+ block in quick on OUTSIDE from 128.0.0.0/16 to any
+ block in quick on OUTSIDE from 128.66.0.0/16 to any
+ block in quick on OUTSIDE from 169.254.0.0/16 to any
+ block in quick on OUTSIDE from 172.16.0.0/12 to any
+ block in quick on OUTSIDE from 191.255.0.0/16 to any
+ block in quick on OUTSIDE from 192.0.0.0/16 to any
+ block in quick on OUTSIDE from 192.168.0.0/16 to any
+ block in quick on OUTSIDE from 197.0.0.0/8 to any
+ block in quick on OUTSIDE from 201.0.0.0/8 to any
+ block in quick on OUTSIDE from 204.152.64.0/23 to any
+ block in quick on OUTSIDE from 224.0.0.0/3 to any
+ block in quick on OUTSIDE from MYNET to any
+ # Your pass rules come here...
+
+ block out on OUTSIDE all
+ block out quick on OUTSIDE from !MYNET to any
+ block out quick on OUTSIDE from MYNET to 0.0.0.0/7
+
+
+
+
+
+
+
+
+
+ -48-
+
+
+ block out quick on OUTSIDE from MYNET to 2.0.0.0/8
+ block out quick on OUTSIDE from MYNET to 5.0.0.0/8
+ block out quick on OUTSIDE from MYNET to 10.0.0.0/8
+ block out quick on OUTSIDE from MYNET to 23.0.0.0/8
+ block out quick on OUTSIDE from MYNET to 27.0.0.0/8
+ block out quick on OUTSIDE from MYNET to 31.0.0.0/8
+ block out quick on OUTSIDE from MYNET to 67.0.0.0/8
+ block out quick on OUTSIDE from MYNET to 68.0.0.0/6
+ block out quick on OUTSIDE from MYNET to 72.0.0.0/5
+ block out quick on OUTSIDE from MYNET to 80.0.0.0/4
+ block out quick on OUTSIDE from MYNET to 96.0.0.0/3
+ block out quick on OUTSIDE from MYNET to 127.0.0.0/8
+ block out quick on OUTSIDE from MYNET to 128.0.0.0/16
+ block out quick on OUTSIDE from MYNET to 128.66.0.0/16
+ block out quick on OUTSIDE from MYNET to 169.254.0.0/16
+ block out quick on OUTSIDE from MYNET to 172.16.0.0/12
+ block out quick on OUTSIDE from MYNET to 191.255.0.0/16
+ block out quick on OUTSIDE from MYNET to 192.0.0.0/16
+ block out quick on OUTSIDE from MYNET to 192.168.0.0/16
+ block out quick on OUTSIDE from MYNET to 197.0.0.0/8
+ block out quick on OUTSIDE from MYNET to 201.0.0.0/8
+ block out quick on OUTSIDE from MYNET to 204.152.64.0/23
+ block out quick on OUTSIDE from MYNET to 224.0.0.0/3
+ # Your pass rules come here...
+
+If you're going to use these, we suggest that you become
+familiar with whois.arin.net and keep an occasional eye on
+these, as the IANA isn't going to notify you when they allo-
+cate one of these to a new corporation or something. You
+have been warned.
+
+ We'd also like to thank Frank DiGennaro <fsd@server-
+vault.com> for greatly contributing to this filter list.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/share/examples/ipfilter/ipf.conf.permissive b/share/examples/ipfilter/ipf.conf.permissive
new file mode 100644
index 000000000000..016c59cadff2
--- /dev/null
+++ b/share/examples/ipfilter/ipf.conf.permissive
@@ -0,0 +1,29 @@
+# augmented rules generated by mkfilters
+block in log quick from any with ipopts
+block in log quick proto tcp from any to any with short
+block in log quick all with opt lsrr
+block in log quick all with opt ssrr
+#-------------------------------------------------------
+# loopback pakets left unmolested
+pass in quick on lo0 all
+pass out quick on lo0 all
+#-------------------------------------------------------
+pass out on ed1 all head 150
+block out from 127.0.0.0/8 to any group 150
+block out from any to 127.0.0.0/8 group 150
+block out from any to 192.168.1.110/32 group 150
+#-------------------------------------------------------
+pass in on ed1 all head 100
+block in from 127.0.0.0/8 to any group 100
+block in from 192.168.1.110/32 to any group 100
+block in from 192.168.0.1/24 to any group 100
+#-------------------------------------------------------
+pass out on fxp0 all head 250
+block out from 127.0.0.0/8 to any group 250
+block out from any to 127.0.0.0/8 group 250
+block out from any to 192.168.0.1/32 group 250
+#-------------------------------------------------------
+pass in on fxp0 all head 200
+block in from 127.0.0.0/8 to any group 200
+block in from 192.168.0.1/32 to any group 200
+block in from 192.168.1.110/24 to any group 200
diff --git a/share/examples/ipfilter/ipf.conf.restrictive b/share/examples/ipfilter/ipf.conf.restrictive
new file mode 100644
index 000000000000..b1b449c8fd77
--- /dev/null
+++ b/share/examples/ipfilter/ipf.conf.restrictive
@@ -0,0 +1,76 @@
+#--------------------------------------------------------------------------
+# ed1 - external interface
+# fxp0 - internal interface
+#--------------------------------------------------------------------------
+# First, nasty packets which we don't want near us at all
+# packets which are too short to be real except echo replies on lo0
+pass in log quick on lo0 proto icmp from 127.0.0.1/8 to 127.0.0.1/8 with short
+block in log quick all with short
+block in log quick all with opt lsrr
+block in log quick all with opt ssrr
+#--------------------------------------------------------------------------
+# loopback packets left unmolested
+pass in log quick on lo0 all
+pass out log quick on lo0 all
+#--------------------------------------------------------------------------
+# Group setup:
+# 100 incoming ed1
+# 150 outgoing ed1
+# 200 incoming fxp0
+# 250 outgoing fxp0
+#--------------------------------------------------------------------------
+block in log body on ed1 all head 100
+block out log body on ed1 all head 150
+#--------------------------------------------------------------------------
+block in log on fxp0 all head 200
+block out log on fxp0 all head 250
+#--------------------------------------------------------------------------
+# incoming ed1 traffic - group 100
+# 1) prevent localhost spoofing
+block in log quick from 127.0.0.1/32 to 192.168.0.0/24 group 100
+block in log quick from 127.0.0.1/32 to 192.168.1.0/24 group 100
+block in log quick from any to 127.0.0.1/8 group 100
+#--------------------------------------------------------------------------
+# 2) deny pakets which should not be seen on th internet (paranoid)
+block in log quick from 10.0.0.0/8 to any group 100
+block in log quick from any to 10.0.0.0/8 group 100
+block in log quick from 172.16.0.0/16 to any group 100
+block in log quick from any to 172.16.0.0/16 group 100
+block in log quick from 192.168.0.0/16 to any group 100
+block in log from any to 192.168.0.0/16 group 100
+# 3) implement policy
+# allow incoming ftp-data
+pass in log quick proto tcp/udp from any to 192.168.1.1/24 keep state group 100
+# if nothing applies, block and return icmp-replies (unreachable and rst)
+block return-icmp(net-unr) in proto udp from any to any group 100
+block return-rst in log proto tcp from any to any group 100
+#--------------------------------------------------------------------------
+# outgoing ed1 traffic - group 150
+# Setup outgoing DNS
+pass out log quick proto tcp/udp from any to 212.40.0.10 port = 53 keep state group 150
+pass out log quick proto tcp/udp from any to 212.40.5.50 port = 53 keep state group 150
+# allow outgoing http-service
+pass out log quick proto tcp from any to any port = 80 flags S/SA keep state keep frags group 150
+# allow outgoing smtp traffic
+pass out log quick proto tcp from 192.168.1.1/24 to any port = 25 flags S/SA keep state group 150
+# allow outgoing pop3 traffic
+pass out log quick proto tcp from 192.168.1.1/24 to any port = 110 flags S/SA keep state group 150
+# allow outgoing ftp traffic
+pass out log quick proto tcp/udp from 192.168.1.1/24 to any port = ftp keep state group 150
+pass out log quick proto icmp from any to any keep state keep frags group 150
+#--------------------------------------------------------------------------
+# incoming traffic on fxp0 - group 200
+#--------------------------------------------------------------------------
+# 1) prevent localhost spoofing
+block in log quick from 127.0.0.0/8 to any group 200
+block in log quick from 192.168.0.1/32 to any group 200
+block in log quick from 192.168.1.110/24 to any group 200
+pass in log quick from any to any group 200
+#--------------------------------------------------------------------------
+# outgoing traffic on fxp0 - group 250
+#--------------------------------------------------------------------------
+block out log quick from 127.0.0.0/8 to any group 250
+block out quick from any to 127.0.0.0/8 group 250
+block out log quick from any to 192.168.0.1/32 group 250
+pass out log quick from any to nay group 250
+#--------------------------------------------------------------------------
diff --git a/share/examples/ipfilter/ipf.conf.sample b/share/examples/ipfilter/ipf.conf.sample
new file mode 100644
index 000000000000..cb47107f88c5
--- /dev/null
+++ b/share/examples/ipfilter/ipf.conf.sample
@@ -0,0 +1,18 @@
+block in log quick from any with ipopts
+block in log quick proto tcp from any to any with short
+pass out on ed1 all head 150
+block out from 127.0.0.0/8 to any group 150
+block out from any to 127.0.0.0/8 group 150
+block out from any to 192.168.1.110/32 group 150
+pass in on ed1 all head 100
+block in from 127.0.0.0/8 to any group 100
+block in from 192.168.1.110/32 to any group 100
+block in from 192.168.0.1/0xffffff00 to any group 100
+pass out on fxp0 all head 250
+block out from 127.0.0.0/8 to any group 250
+block out from any to 127.0.0.0/8 group 250
+block out from any to 192.168.0.1/32 group 250
+pass in on fxp0 all head 200
+block in from 127.0.0.0/8 to any group 200
+block in from 192.168.0.1 to any group 200
+block in from 192.168.1.110/0xffffff00 to any group 200
diff --git a/share/examples/ipfilter/ipnat.conf.sample b/share/examples/ipfilter/ipnat.conf.sample
new file mode 100644
index 000000000000..f20d895936ef
--- /dev/null
+++ b/share/examples/ipfilter/ipnat.conf.sample
@@ -0,0 +1,2 @@
+map ed1 192.168.0.0/24 -> 192.168.1.110/32 portmap tcp/udp 40000:65000
+map ed1 192.168.0.0/24 -> 192.168.1.110/32
diff --git a/share/examples/ipfilter/l4check/Makefile b/share/examples/ipfilter/l4check/Makefile
new file mode 100644
index 000000000000..e7366b63ad6a
--- /dev/null
+++ b/share/examples/ipfilter/l4check/Makefile
@@ -0,0 +1,10 @@
+# For Solaris
+#LIBS=-lsocket -lnsl
+
+all: l4check
+
+l4check: l4check.c
+ $(CC) -g -I.. $(CFLAGS) $(LIBS) l4check.c -o $@
+
+clean:
+ /bin/rm -f l4check
diff --git a/share/examples/ipfilter/l4check/http.check b/share/examples/ipfilter/l4check/http.check
new file mode 100644
index 000000000000..56d93d9281a6
--- /dev/null
+++ b/share/examples/ipfilter/l4check/http.check
@@ -0,0 +1,2 @@
+GET /
+
diff --git a/share/examples/ipfilter/l4check/http.ok b/share/examples/ipfilter/l4check/http.ok
new file mode 100644
index 000000000000..2b5d2c15266d
--- /dev/null
+++ b/share/examples/ipfilter/l4check/http.ok
@@ -0,0 +1 @@
+<HTML> \ No newline at end of file
diff --git a/share/examples/ipfilter/l4check/l4check.c b/share/examples/ipfilter/l4check/l4check.c
new file mode 100644
index 000000000000..2e80b7531b4e
--- /dev/null
+++ b/share/examples/ipfilter/l4check/l4check.c
@@ -0,0 +1,800 @@
+
+/*
+ * (C)Copyright (C) 2012 by Darren Reed.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <net/if.h>
+
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ip_nat.h"
+
+#include "ipf.h"
+
+extern char *optarg;
+
+
+typedef struct l4cfg {
+ struct l4cfg *l4_next;
+ struct ipnat l4_nat; /* NAT rule */
+ struct sockaddr_in l4_sin; /* remote socket to connect */
+ time_t l4_last; /* when we last connected */
+ int l4_alive; /* 1 = remote alive */
+ int l4_fd;
+ int l4_rw; /* 0 = reading, 1 = writing */
+ char *l4_rbuf; /* read buffer */
+ int l4_rsize; /* size of buffer */
+ int l4_rlen; /* how much used */
+ char *l4_wptr; /* next byte to write */
+ int l4_wlen; /* length yet to be written */
+} l4cfg_t;
+
+
+l4cfg_t *l4list = NULL;
+char *response = NULL;
+char *probe = NULL;
+l4cfg_t template;
+int frequency = 20;
+int ctimeout = 1;
+int rtimeout = 1;
+size_t plen = 0;
+size_t rlen = 0;
+int natfd = -1;
+int opts = 0;
+
+#if defined(sun) && !defined(__svr4__) && !defined(__SVR4)
+# define strerror(x) sys_errlist[x]
+#endif
+
+
+char *
+copystr(char *dst, char *src)
+{
+ register char *s, *t, c;
+ register int esc = 0;
+
+ for (s = src, t = dst; s && t && (c = *s++); )
+ if (esc) {
+ esc = 0;
+ switch (c)
+ {
+ case 'n' :
+ *t++ = '\n';
+ break;
+ case 'r' :
+ *t++ = '\r';
+ break;
+ case 't' :
+ *t++ = '\t';
+ break;
+ }
+ } else if (c != '\\')
+ *t++ = c;
+ else
+ esc = 1;
+ *t = '\0';
+ return(dst);
+}
+
+void
+addnat(l4cfg_t *l4)
+{
+ ipnat_t *ipn = &l4->l4_nat;
+
+ printf("Add NAT rule for %s/%#x,%u -> ", inet_ntoa(ipn->in_out[0]),
+ ipn->in_outmsk, ntohs(ipn->in_pmin));
+ printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ntohs(ipn->in_pnext));
+ if (!(opts & OPT_DONOTHING)) {
+ if (ioctl(natfd, SIOCADNAT, &ipn) == -1)
+ perror("ioctl(SIOCADNAT)");
+ }
+}
+
+
+void
+delnat(l4cfg_t *l4)
+{
+ ipnat_t *ipn = &l4->l4_nat;
+
+ printf("Remove NAT rule for %s/%#x,%u -> ",
+ inet_ntoa(ipn->in_out[0]), ipn->in_outmsk, ipn->in_pmin);
+ printf("%s,%u\n", inet_ntoa(ipn->in_in[0]), ipn->in_pnext);
+ if (!(opts & OPT_DONOTHING)) {
+ if (ioctl(natfd, SIOCRMNAT, &ipn) == -1)
+ perror("ioctl(SIOCRMNAT)");
+ }
+}
+
+
+void
+connectl4(l4cfg_t *l4)
+{
+ l4->l4_rw = 1;
+ l4->l4_rlen = 0;
+ l4->l4_wlen = plen;
+ if (!l4->l4_wlen) {
+ l4->l4_alive = 1;
+ addnat(l4);
+ } else
+ l4->l4_wptr = probe;
+}
+
+
+void
+closel4(l4cfg_t *l4, int dead)
+{
+ close(l4->l4_fd);
+ l4->l4_fd = -1;
+ l4->l4_rw = -1;
+ if (dead && l4->l4_alive) {
+ l4->l4_alive = 0;
+ delnat(l4);
+ }
+}
+
+
+void
+connectfd(l4cfg_t *l4)
+{
+ if (connect(l4->l4_fd, (struct sockaddr *)&l4->l4_sin,
+ sizeof(l4->l4_sin)) == -1) {
+ if (errno == EISCONN) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Connected fd %d\n",
+ l4->l4_fd);
+ connectl4(l4);
+ return;
+ }
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Connect failed fd %d: %s\n",
+ l4->l4_fd, strerror(errno));
+ closel4(l4, 1);
+ return;
+ }
+ l4->l4_rw = 1;
+}
+
+
+void
+writefd(l4cfg_t *l4)
+{
+ char buf[80], *ptr;
+ int n, i, fd;
+
+ fd = l4->l4_fd;
+
+ if (l4->l4_rw == -2) {
+ connectfd(l4);
+ return;
+ }
+
+ n = l4->l4_wlen;
+
+ i = send(fd, l4->l4_wptr, n, 0);
+ if (i == 0 || i == -1) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Send on fd %d failed: %s\n",
+ fd, strerror(errno));
+ closel4(l4, 1);
+ } else {
+ l4->l4_wptr += i;
+ l4->l4_wlen -= i;
+ if (l4->l4_wlen == 0)
+ l4->l4_rw = 0;
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Sent %d bytes to fd %d\n", i, fd);
+ }
+}
+
+
+void readfd(l4cfg_t *l4)
+{
+ char buf[80], *ptr;
+ int n, i, fd;
+
+ fd = l4->l4_fd;
+
+ if (l4->l4_rw == -2) {
+ connectfd(l4);
+ return;
+ }
+
+ if (l4->l4_rsize) {
+ n = l4->l4_rsize - l4->l4_rlen;
+ ptr = l4->l4_rbuf + l4->l4_rlen;
+ } else {
+ n = sizeof(buf) - 1;
+ ptr = buf;
+ }
+
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Read %d bytes on fd %d to %p\n",
+ n, fd, ptr);
+ i = recv(fd, ptr, n, 0);
+ if (i == 0 || i == -1) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Read error on fd %d: %s\n",
+ fd, (i == 0) ? "EOF" : strerror(errno));
+ closel4(l4, 1);
+ } else {
+ if (ptr == buf)
+ ptr[i] = '\0';
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "%d: Read %d bytes [%*.*s]\n",
+ fd, i, i, i, ptr);
+ if (ptr != buf) {
+ l4->l4_rlen += i;
+ if (l4->l4_rlen >= l4->l4_rsize) {
+ if (!strncmp(response, l4->l4_rbuf,
+ l4->l4_rsize)) {
+ printf("%d: Good response\n",
+ fd);
+ if (!l4->l4_alive) {
+ l4->l4_alive = 1;
+ addnat(l4);
+ }
+ closel4(l4, 0);
+ } else {
+ if (opts & OPT_VERBOSE)
+ printf("%d: Bad response\n",
+ fd);
+ closel4(l4, 1);
+ }
+ }
+ } else if (!l4->l4_alive) {
+ l4->l4_alive = 1;
+ addnat(l4);
+ closel4(l4, 0);
+ }
+ }
+}
+
+
+int
+runconfig(void)
+{
+ int fd, opt, res, mfd, i;
+ struct timeval tv;
+ time_t now, now1;
+ fd_set rfd, wfd;
+ l4cfg_t *l4;
+
+ mfd = 0;
+ opt = 1;
+ now = time(NULL);
+
+ /*
+ * First, initiate connections that are closed, as required.
+ */
+ for (l4 = l4list; l4; l4 = l4->l4_next) {
+ if ((l4->l4_last + frequency < now) && (l4->l4_fd == -1)) {
+ l4->l4_last = now;
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd == -1)
+ continue;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt,
+ sizeof(opt));
+#ifdef O_NONBLOCK
+ if ((res = fcntl(fd, F_GETFL, 0)) != -1)
+ fcntl(fd, F_SETFL, res | O_NONBLOCK);
+#endif
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "Connecting to %s,%d (fd %d)...",
+ inet_ntoa(l4->l4_sin.sin_addr),
+ ntohs(l4->l4_sin.sin_port), fd);
+ if (connect(fd, (struct sockaddr *)&l4->l4_sin,
+ sizeof(l4->l4_sin)) == -1) {
+ if (errno != EINPROGRESS) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "failed\n");
+ perror("connect");
+ close(fd);
+ fd = -1;
+ } else {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "waiting\n");
+ l4->l4_rw = -2;
+ }
+ } else {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "connected\n");
+ connectl4(l4);
+ }
+ l4->l4_fd = fd;
+ }
+ }
+
+ /*
+ * Now look for fd's which we're expecting to read/write from.
+ */
+ FD_ZERO(&rfd);
+ FD_ZERO(&wfd);
+ tv.tv_sec = MIN(rtimeout, ctimeout);
+ tv.tv_usec = 0;
+
+ for (l4 = l4list; l4; l4 = l4->l4_next)
+ if (l4->l4_rw == 0) {
+ if (now - l4->l4_last > rtimeout) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "%d: Read timeout\n",
+ l4->l4_fd);
+ closel4(l4, 1);
+ continue;
+ }
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Wait for read on fd %d\n",
+ l4->l4_fd);
+ FD_SET(l4->l4_fd, &rfd);
+ if (l4->l4_fd > mfd)
+ mfd = l4->l4_fd;
+ } else if ((l4->l4_rw == 1 && l4->l4_wlen) ||
+ l4->l4_rw == -2) {
+ if ((l4->l4_rw == -2) &&
+ (now - l4->l4_last > ctimeout)) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "%d: connect timeout\n",
+ l4->l4_fd);
+ closel4(l4);
+ continue;
+ }
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Wait for write on fd %d\n",
+ l4->l4_fd);
+ FD_SET(l4->l4_fd, &wfd);
+ if (l4->l4_fd > mfd)
+ mfd = l4->l4_fd;
+ }
+
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Select: max fd %d wait %d\n", mfd + 1,
+ tv.tv_sec);
+ i = select(mfd + 1, &rfd, &wfd, NULL, &tv);
+ if (i == -1) {
+ perror("select");
+ return(-1);
+ }
+
+ now1 = time(NULL);
+
+ for (l4 = l4list; (i > 0) && l4; l4 = l4->l4_next) {
+ if (l4->l4_fd < 0)
+ continue;
+ if (FD_ISSET(l4->l4_fd, &rfd)) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Ready to read on fd %d\n",
+ l4->l4_fd);
+ readfd(l4);
+ i--;
+ }
+
+ if ((l4->l4_fd >= 0) && FD_ISSET(l4->l4_fd, &wfd)) {
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Ready to write on fd %d\n",
+ l4->l4_fd);
+ writefd(l4);
+ i--;
+ }
+ }
+ return(0);
+}
+
+
+int
+gethostport(char *str, int lnum, u_32_t *ipp, u_short *portp)
+{
+ struct servent *sp;
+ struct hostent *hp;
+ char *host, *port;
+ struct in_addr ip;
+
+ host = str;
+ port = strchr(host, ',');
+ if (port)
+ *port++ = '\0';
+
+#ifdef HAVE_INET_ATON
+ if (ISDIGIT(*host) && inet_aton(host, &ip))
+ *ipp = ip.s_addr;
+#else
+ if (ISDIGIT(*host))
+ *ipp = inet_addr(host);
+#endif
+ else {
+ if (!(hp = gethostbyname(host))) {
+ fprintf(stderr, "%d: can't resolve hostname: %s\n",
+ lnum, host);
+ return(0);
+ }
+ *ipp = *(u_32_t *)hp->h_addr;
+ }
+
+ if (port) {
+ if (ISDIGIT(*port))
+ *portp = htons(atoi(port));
+ else {
+ sp = getservbyname(port, "tcp");
+ if (sp)
+ *portp = sp->s_port;
+ else {
+ fprintf(stderr, "%d: unknown service %s\n",
+ lnum, port);
+ return(0);
+ }
+ }
+ } else
+ *portp = 0;
+ return(1);
+}
+
+
+char *
+mapfile(char *file, size_t *sizep)
+{
+ struct stat sb;
+ caddr_t addr;
+ int fd;
+
+ fd = open(file, O_RDONLY);
+ if (fd == -1) {
+ perror("open(mapfile)");
+ return(NULL);
+ }
+
+ if (fstat(fd, &sb) == -1) {
+ perror("fstat(mapfile)");
+ close(fd);
+ return(NULL);
+ }
+
+ addr = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (addr == (caddr_t)-1) {
+ perror("mmap(mapfile)");
+ close(fd);
+ return(NULL);
+ }
+ close(fd);
+ *sizep = sb.st_size;
+ return(char *)addr;
+}
+
+
+int
+readconfig(char *filename)
+{
+ char c, buf[512], *s, *t, *errtxt = NULL, *line;
+ int num, err = 0;
+ ipnat_t *ipn;
+ l4cfg_t *l4;
+ FILE *fp;
+
+ fp = fopen(filename, "r");
+ if (!fp) {
+ perror("open(configfile)");
+ return(-1);
+ }
+
+ bzero((char *)&template, sizeof(template));
+ template.l4_fd = -1;
+ template.l4_rw = -1;
+ template.l4_sin.sin_family = AF_INET;
+ ipn = &template.l4_nat;
+ ipn->in_flags = IPN_TCP|IPN_ROUNDR;
+ ipn->in_redir = NAT_REDIRECT;
+
+ for (num = 1; fgets(buf, sizeof(buf), fp); num++) {
+ s = strchr(buf, '\n');
+ if (!s) {
+ fprintf(stderr, "%d: line too long\n", num);
+ fclose(fp);
+ return(-1);
+ }
+
+ *s = '\0';
+
+ /*
+ * lines which are comments
+ */
+ s = strchr(buf, '#');
+ if (s)
+ *s = '\0';
+
+ /*
+ * Skip leading whitespace
+ */
+ for (line = buf; (c = *line) && ISSPACE(c); line++)
+ ;
+ if (!*line)
+ continue;
+
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Parsing: [%s]\n", line);
+ t = strtok(line, " \t");
+ if (!t)
+ continue;
+ if (!strcasecmp(t, "interface")) {
+ s = strtok(NULL, " \t");
+ if (s)
+ t = strtok(NULL, "\t");
+ if (!s || !t) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+
+ if (!strchr(t, ',')) {
+ fprintf(stderr,
+ "%d: local address,port missing\n",
+ num);
+ err = -1;
+ break;
+ }
+
+ strncpy(ipn->in_ifname, s, sizeof(ipn->in_ifname));
+ if (!gethostport(t, num, &ipn->in_outip,
+ &ipn->in_pmin)) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ ipn->in_outmsk = 0xffffffff;
+ ipn->in_pmax = ipn->in_pmin;
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "Interface %s %s/%#x port %u\n",
+ ipn->in_ifname,
+ inet_ntoa(ipn->in_out[0]),
+ ipn->in_outmsk, ipn->in_pmin);
+ } else if (!strcasecmp(t, "remote")) {
+ if (!*ipn->in_ifname) {
+ fprintf(stderr,
+ "%d: ifname not set prior to remote\n",
+ num);
+ err = -1;
+ break;
+ }
+ s = strtok(NULL, " \t");
+ if (s)
+ t = strtok(NULL, "");
+ if (!s || !t || strcasecmp(s, "server")) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+
+ ipn->in_pnext = 0;
+ if (!gethostport(t, num, &ipn->in_inip,
+ &ipn->in_pnext)) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ ipn->in_inmsk = 0xffffffff;
+ if (ipn->in_pnext == 0)
+ ipn->in_pnext = ipn->in_pmin;
+
+ l4 = (l4cfg_t *)malloc(sizeof(*l4));
+ if (!l4) {
+ fprintf(stderr, "%d: out of memory (%d)\n",
+ num, sizeof(*l4));
+ err = -1;
+ break;
+ }
+ bcopy((char *)&template, (char *)l4, sizeof(*l4));
+ l4->l4_sin.sin_addr = ipn->in_in[0];
+ l4->l4_sin.sin_port = ipn->in_pnext;
+ l4->l4_next = l4list;
+ l4list = l4;
+ } else if (!strcasecmp(t, "connect")) {
+ s = strtok(NULL, " \t");
+ if (s)
+ t = strtok(NULL, "\t");
+ if (!s || !t) {
+ errtxt = line;
+ err = -1;
+ break;
+ } else if (!strcasecmp(s, "timeout")) {
+ ctimeout = atoi(t);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "connect timeout %d\n",
+ ctimeout);
+ } else if (!strcasecmp(s, "frequency")) {
+ frequency = atoi(t);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "connect frequency %d\n",
+ frequency);
+ } else {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ } else if (!strcasecmp(t, "probe")) {
+ s = strtok(NULL, " \t");
+ if (!s) {
+ errtxt = line;
+ err = -1;
+ break;
+ } else if (!strcasecmp(s, "string")) {
+ if (probe) {
+ fprintf(stderr,
+ "%d: probe already set\n",
+ num);
+ err = -1;
+ break;
+ }
+ t = strtok(NULL, "");
+ if (!t) {
+ fprintf(stderr,
+ "%d: No probe string\n", num);
+ err = -1;
+ break;
+ }
+
+ probe = malloc(strlen(t));
+ copystr(probe, t);
+ plen = strlen(probe);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Probe string [%s]\n",
+ probe);
+ } else if (!strcasecmp(s, "file")) {
+ t = strtok(NULL, " \t");
+ if (!t) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ if (probe) {
+ fprintf(stderr,
+ "%d: probe already set\n",
+ num);
+ err = -1;
+ break;
+ }
+ probe = mapfile(t, &plen);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "Probe file %s len %u@%p\n",
+ t, plen, probe);
+ }
+ } else if (!strcasecmp(t, "response")) {
+ s = strtok(NULL, " \t");
+ if (!s) {
+ errtxt = line;
+ err = -1;
+ break;
+ } else if (!strcasecmp(s, "timeout")) {
+ t = strtok(NULL, " \t");
+ if (!t) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ rtimeout = atoi(t);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "response timeout %d\n",
+ rtimeout);
+ } else if (!strcasecmp(s, "string")) {
+ if (response) {
+ fprintf(stderr,
+ "%d: response already set\n",
+ num);
+ err = -1;
+ break;
+ }
+ response = strdup(strtok(NULL, ""));
+ rlen = strlen(response);
+ template.l4_rsize = rlen;
+ template.l4_rbuf = malloc(rlen);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "Response string [%s]\n",
+ response);
+ } else if (!strcasecmp(s, "file")) {
+ t = strtok(NULL, " \t");
+ if (!t) {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ if (response) {
+ fprintf(stderr,
+ "%d: response already set\n",
+ num);
+ err = -1;
+ break;
+ }
+ response = mapfile(t, &rlen);
+ template.l4_rsize = rlen;
+ template.l4_rbuf = malloc(rlen);
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr,
+ "Response file %s len %u@%p\n",
+ t, rlen, response);
+ }
+ } else {
+ errtxt = line;
+ err = -1;
+ break;
+ }
+ }
+
+ if (errtxt)
+ fprintf(stderr, "%d: syntax error at \"%s\"\n", num, errtxt);
+ fclose(fp);
+ return(err);
+}
+
+
+void
+usage(char *prog)
+{
+ fprintf(stderr, "Usage: %s -f <configfile>\n", prog);
+ exit(1);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ char *config = NULL;
+ int c;
+
+ while ((c = getopt(argc, argv, "f:nv")) != -1)
+ switch (c)
+ {
+ case 'f' :
+ config = optarg;
+ break;
+ case 'n' :
+ opts |= OPT_DONOTHING;
+ break;
+ case 'v' :
+ opts |= OPT_VERBOSE;
+ break;
+ }
+
+ if (config == NULL)
+ usage(argv[0]);
+
+ if (readconfig(config))
+ exit(1);
+
+ if (!l4list) {
+ fprintf(stderr, "No remote servers, exiting.");
+ exit(1);
+ }
+
+ if (!(opts & OPT_DONOTHING)) {
+ natfd = open(IPL_NAT, O_RDWR);
+ if (natfd == -1) {
+ perror("open(IPL_NAT)");
+ exit(1);
+ }
+ }
+
+ if (opts & OPT_VERBOSE)
+ fprintf(stderr, "Starting...\n");
+ while (runconfig() == 0)
+ ;
+}
diff --git a/share/examples/ipfilter/l4check/l4check.conf b/share/examples/ipfilter/l4check/l4check.conf
new file mode 100644
index 000000000000..d000e9fc5b48
--- /dev/null
+++ b/share/examples/ipfilter/l4check/l4check.conf
@@ -0,0 +1,31 @@
+#
+# NOTE: ORDER IS IMPORTANT IN THIS FILE
+#
+# Interface to do the redirections on and the IP address which will be
+# targeted.
+#
+interface nf0 192.168.1.1,2100
+#
+connect timeout 1
+connect frequency 20
+#
+# If no probe string is specified, a successful connection implies the
+# server is still alive.
+#
+probe string GET /\n\n
+#probe file http.check
+#
+response timeout 4
+response string <HTML>
+#response file http.ok
+#
+# Here we have multiple servers, listed because that's what happens to be
+# used for testing of connect timeoutes, read timeouts, success and things
+# which don't connect.
+#
+remote server 192.168.1.2,23
+remote server 192.168.1.2,2101
+remote server 192.168.1.3,25
+remote server 192.168.1.254,8000
+remote server 192.168.1.1,9
+#
diff --git a/share/examples/ipfilter/mkfilters b/share/examples/ipfilter/mkfilters
new file mode 100644
index 000000000000..fe15c55563ab
--- /dev/null
+++ b/share/examples/ipfilter/mkfilters
@@ -0,0 +1,116 @@
+#!/usr/local/bin/perl
+# for best results, bring up all your interfaces before running this
+
+if ($^O =~ m/^irix/i)
+{
+ &irix_mkfilters || regular_mkfilters || die $!;
+}
+else
+{
+ &regular_mkfilters || irix_mkfilters || die $!;
+}
+
+foreach $i (keys %ifaces) {
+ $net{$i} = $inet{$i}."/".$netmask{$i} if (defined($inet{$i}));
+}
+#
+# print out route suggestions
+#
+print "#\n";
+print "# The following routes should be configured, if not already:\n";
+print "#\n";
+foreach $i (keys %ifaces) {
+ next if (($i =~ /lo/) || !defined($net{$i}) || defined($ppp{$i}));
+ print "# route add $inet{$i} localhost 0\n";
+}
+print "#\n";
+
+#
+# print out some generic filters which people should use somewhere near the top
+#
+print "block in log quick from any to any with ipopts\n";
+print "block in log quick proto tcp from any to any with short\n";
+
+$grpi = 0;
+
+foreach $i (keys %ifaces) {
+ if (!defined($inet{$i})) {
+ next;
+ }
+
+ $grpi += 100;
+ $grpo = $grpi + 50;
+
+ if ($i !~ /lo/) {
+ print "pass out on $i all head $grpo\n";
+ print "block out from 127.0.0.0/8 to any group $grpo\n";
+ print "block out from any to 127.0.0.0/8 group $grpo\n";
+ print "block out from any to $inet{$i}/32 group $grpo\n";
+ print "pass in on $i all head $grpi\n";
+ print "block in from 127.0.0.0/8 to any group $grpi\n";
+ print "block in from $inet{$i}/32 to any group $grpi\n";
+ foreach $j (keys %ifaces) {
+ if ($i ne $j && $j !~ /^lo/ && defined($net{$j})) {
+ print "block in from $net{$j} to any group $grpi\n";
+ }
+ }
+ }
+}
+
+sub irix_mkfilters
+{
+ open(NETSTAT, "/usr/etc/netstat -i|") || return 0;
+
+ while (defined($line = <NETSTAT>))
+ {
+ if ($line =~ m/^Name/)
+ {
+ next;
+ }
+ elsif ($line =~ m/^(\S+)/)
+ {
+ open(I, "/usr/etc/ifconfig $1|") || return 0;
+ &scan_ifconfig;
+ close I; # being neat... - Allen
+ }
+ }
+ close NETSTAT; # again, being neat... - Allen
+ return 1;
+}
+
+sub regular_mkfilters
+{
+ open(I, "ifconfig -a|") || return 0;
+ &scan_ifconfig;
+ close I; # being neat... - Allen
+ return 1;
+}
+
+sub scan_ifconfig
+{
+ while (<I>) {
+ chop;
+ if (/^[a-zA-Z]+\d+:/) {
+ ($iface = $_) =~ s/^([a-zA-Z]+\d+).*/$1/;
+ $ifaces{$iface} = $iface;
+ next;
+ }
+ if (/inet/) {
+ if (/\-\-\>/) { # PPP, (SLIP?)
+ ($inet{$iface} = $_) =~ s/.*inet ([^ ]+) \-\-\> ([^ ]+).*/$1/;
+ ($ppp{$iface} = $_) =~ s/.*inet ([^ ]+) \-\-\> ([^ ]+).*/$2/;
+ } else {
+ ($inet{$iface} = $_) =~ s/.*inet ([^ ]+).*/$1/;
+ }
+ }
+ if (/netmask/) {
+ ($mask = $_) =~ s/.*netmask ([^ ]+).*/$1/;
+ $mask =~ s/^/0x/ if ($mask =~ /^[0-9a-f]*$/);
+ $netmask{$iface} = $mask;
+ }
+ if (/broadcast/) {
+ ($bcast{$iface} = $_) =~ s/.*broadcast ([^ ]+).*/$1/;
+ }
+ }
+}
+
diff --git a/share/examples/ipfilter/mkfilters.1 b/share/examples/ipfilter/mkfilters.1
new file mode 100644
index 000000000000..65afaec4019e
--- /dev/null
+++ b/share/examples/ipfilter/mkfilters.1
@@ -0,0 +1,15 @@
+.\"
+.TH MKFILTERS 1
+.SH NAME
+mkfilters \- generate a minimal firewall ruleset for ipfilter
+.SH SYNOPSIS
+.B mkfilters
+.SH FILES
+/usr/share/examples/ipfilter/mkfilters
+.SH DESCRIPTION
+.PP
+\fBmkfilters\fP is a perl script that generates a minimal filter rule set for
+use with \fBipfilter\fP by parsing the output of \fBifconfig\fP.
+.DT
+.SH SEE ALSO
+ipf(8), ipf(5), ipfilter(5), ifconfig(8)
diff --git a/share/examples/ipfilter/mlfk_rule.c b/share/examples/ipfilter/mlfk_rule.c
new file mode 100644
index 000000000000..9126e4d97281
--- /dev/null
+++ b/share/examples/ipfilter/mlfk_rule.c
@@ -0,0 +1,69 @@
+
+/*
+ * Copyright (C) 2012 by Darren Reed.
+ *
+ * See the IPFILTER.LICENCE file for details on licencing.
+ *
+ * $Id$
+ */
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+
+#include <netinet/ipl.h>
+#include <netinet/ip_compat.h>
+#include <netinet/ip_fil.h>
+#include <netinet/ip_state.h>
+#include <netinet/ip_nat.h>
+#include <netinet/ip_auth.h>
+#include <netinet/ip_frag.h>
+
+#include "ip_rules.h"
+
+extern ipf_main_softc_t ipfmain;
+
+static int
+ipfrule_modevent(module_t mod, int type, void *unused)
+{
+ int error = 0;
+
+ switch (type)
+ {
+ case MOD_LOAD :
+ error = ipfrule_add();
+ if (!error)
+ ipfmain.ipf_refcnt++;
+ break;
+ case MOD_UNLOAD :
+ error = ipfrule_remove();
+ if (!error)
+ ipfmain.ipf_refcnt--;
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return(error);
+}
+
+static moduledata_t ipfrulemod = {
+ "ipfrule",
+ ipfrule_modevent,
+ 0
+};
+DECLARE_MODULE(ipfrule, ipfrulemod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);
+#ifdef MODULE_DEPEND
+MODULE_DEPEND(ipfrule, ipfilter, 1, 1, 1);
+#endif
+#ifdef MODULE_VERSION
+MODULE_VERSION(ipfrule, 1);
+#endif
diff --git a/share/examples/ipfilter/rules.txt b/share/examples/ipfilter/rules.txt
new file mode 100644
index 000000000000..f8ceb8a4352c
--- /dev/null
+++ b/share/examples/ipfilter/rules.txt
@@ -0,0 +1,181 @@
+#
+# block all incoming TCP packets on le0 from host "foo" to any destination.
+#
+block in on le0 proto tcp from foo/32 to any
+
+ ------------------------------------------------------------------------
+
+#
+# block all outgoing TCP packets on le0 from any host to port 23 of host bar.
+#
+block out on le0 proto tcp from any to bar/32 port != 23
+
+ ------------------------------------------------------------------------
+
+#
+# block all inbound packets.
+#
+block in from any to any
+#
+# pass through packets to and from localhost.
+#
+pass in from 127.0.0.1/32 to 127.0.0.1/32
+#
+# allow a variety of individual hosts to send any type of IP packet to any
+# other host.
+#
+pass in from 10.1.3.1 to any
+pass in from 10.1.3.2 to any
+pass in from 10.1.3.3 to any
+pass in from 10.1.3.4 to any
+pass in from 10.1.3.5 to any
+pass in from 10.1.0.13/32 to any
+pass in from 10.1.1.1/32 to any
+pass in from 10.1.2.1/32 to any
+#
+#
+# block all outbound packets.
+#
+block out from any to any
+#
+# allow any packets destined for localhost out.
+#
+pass out from any to 127.0.0.1/32
+#
+# allow any host to send any IP packet out to a limited number of hosts.
+#
+pass out from any to 10.1.3.1/32
+pass out from any to 10.1.3.2/32
+pass out from any to 10.1.3.3/32
+pass out from any to 10.1.3.4/32
+pass out from any to 10.1.3.5/32
+pass out from any to 10.1.0.13/32
+pass out from any to 10.1.1.1/32
+pass out from any to 10.1.2.1/32
+
+ ------------------------------------------------------------------------
+
+#
+# block all ICMP packets.
+#
+block in proto icmp from any to any
+
+ ------------------------------------------------------------------------
+
+#
+# test ruleset
+#
+# allow packets coming from foo to bar through.
+#
+pass from foo to bar
+#
+# allow any TCP packets from the same subnet as foo is on through to host
+# 10.1.1.2 if they are destined for port 6667.
+#
+pass proto tcp from fubar/24 to 10.1.1.2/32 port = 6667
+#
+# allow in UDP packets which are NOT from port 53 and are destined for
+# localhost
+#
+pass proto udp from fubar port != 53 to localhost
+#
+# block all ICMP unreachables.
+#
+block from any to any icmp unreach
+#
+# allow packets through which have a non-standard IP header length (ie there
+# are IP options such as source-routing present).
+#
+pass from any to any with ipopts
+
+ ------------------------------------------------------------------------
+
+#
+# block all TCP packets with only the SYN flag set (this is the first
+# packet sent to establish a connection).
+#
+block in proto tcp from any to any flags S/SA
+
+ ------------------------------------------------------------------------
+
+#
+# log all inbound packet on le0 which has IP options present
+#
+log in on le0 from any to any with ipopts
+#
+# block any inbound packets on le0 which are fragmented and "too short" to
+# do any meaningful comparison on. This actually only applies to TCP
+# packets which can be missing the flags/ports (depending on which part
+# of the fragment you see).
+#
+block in log quick on le0 from any to any with short frag
+#
+# log all inbound TCP packets with the SYN flag (only) set
+# (NOTE: if it were an inbound TCP packet with the SYN flag set and it
+# had IP options present, this rule and the above would cause it
+# to be logged twice).
+#
+log in on le0 proto tcp from any to any flags S/SA
+#
+# block and log any inbound ICMP unreachables
+#
+block in log on le0 proto icmp from any to any icmp-type unreach
+#
+# block and log any inbound UDP packets on le0 which are going to port 2049
+# (the NFS port).
+#
+block in log on le0 proto udp from any to any port = 2049
+#
+# quickly allow any packets to/from a particular pair of hosts
+#
+pass in quick from any to 10.1.3.2/32
+pass in quick from any to 10.1.0.13/32
+pass in quick from 10.1.3.2/32 to any
+pass in quick from 10.1.0.13/32 to any
+#
+# block (and stop matching) any packet with IP options present.
+#
+block in quick on le0 from any to any with ipopts
+#
+# allow any packet through
+#
+pass in from any to any
+#
+# block any inbound UDP packets destined for these subnets.
+#
+block in on le0 proto udp from any to 10.1.3.0/24
+block in on le0 proto udp from any to 10.1.1.0/24
+block in on le0 proto udp from any to 10.1.2.0/24
+#
+# block any inbound TCP packets with only the SYN flag set that are
+# destined for these subnets.
+#
+block in on le0 proto tcp from any to 10.1.3.0/24 flags S/SA
+block in on le0 proto tcp from any to 10.1.2.0/24 flags S/SA
+block in on le0 proto tcp from any to 10.1.1.0/24 flags S/SA
+#
+# block any inbound ICMP packets destined for these subnets.
+#
+block in on le0 proto icmp from any to 10.1.3.0/24
+block in on le0 proto icmp from any to 10.1.1.0/24
+block in on le0 proto icmp from any to 10.1.2.0/24
+#
+# Log all short TCP packets to qe3, with "packetlog" as the intended
+# destination for the packet.
+#
+block in to qe3:packetlog proto tcp all with short
+#
+# Log all connection attempts for TCP
+#
+pass in dup-to le0:packetlog proto tcp all flags S/SA
+#
+# Route all UDP packets through transparently.
+#
+pass in fastroute proto udp all
+#
+# Route all ICMP packets to network 10 out through le1, to "router"
+#
+pass in to le1:router proto icmp all
+
+ ------------------------------------------------------------------------
+Return to the IP Filter home page
diff --git a/share/examples/ipfilter/rules/BASIC.NAT b/share/examples/ipfilter/rules/BASIC.NAT
new file mode 100644
index 000000000000..213e33815c19
--- /dev/null
+++ b/share/examples/ipfilter/rules/BASIC.NAT
@@ -0,0 +1,46 @@
+#!/sbin/ipnat -f -
+#
+# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3
+#
+# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32
+#
+# ed0 - (internal) network interface, address w.x.y.z/32
+#
+# If we have only 1 valid IP address from our ISP, then we do this:
+#
+# To make ftp work, using the internal ftp proxy, use:
+#
+map ppp0 w.x.y.z/24 -> a.b.c.d/32 proxy port ftp ftp/tcp
+#
+# For normal TCP/UDP and other IP protocols
+#
+map ppp0 w.x.y.z/24 -> a.b.c.d/32 portmap tcp/udp 40000:60000
+map ppp0 w.x.y.z/24 -> a.b.c.d/32
+#
+# if we get a different dialup IP address each time, then we would use:
+#
+#map ppp0 w.x.y.z/24 -> 0/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.z/24 -> 0/32
+#
+# If we have a class C address space of valid IP#'s from our ISP, then we can
+# do this:
+#
+#map ppp0 w.x.y.z/24 -> a.b.c.d/24 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.z/24 -> a.b.c.d/24
+#
+# or, if we only have a small number of PC's, this:
+#
+#map ppp0 w.x.y.v/32 -> a.b.c.E/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.v/32 -> a.b.c.E/32
+#map ppp0 w.x.y.u/32 -> a.b.c.F/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.u/32 -> a.b.c.F/32
+#map ppp0 w.x.y.t/32 -> a.b.c.G/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.t/32 -> a.b.c.G/32
+#map ppp0 w.x.y.s/32 -> a.b.c.H/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.s/32 -> a.b.c.H/32
+#map ppp0 w.x.y.r/32 -> a.b.c.I/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.r/32 -> a.b.c.I/32
+#map ppp0 w.x.y.q/32 -> a.b.c.J/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.q/32 -> a.b.c.J/32
+#map ppp0 w.x.y.p/32 -> a.b.c.K/32 portmap tcp/udp 40000:60000
+#map ppp0 w.x.y.p/32 -> a.b.c.K/32
diff --git a/share/examples/ipfilter/rules/BASIC_1.FW b/share/examples/ipfilter/rules/BASIC_1.FW
new file mode 100644
index 000000000000..642dde061efd
--- /dev/null
+++ b/share/examples/ipfilter/rules/BASIC_1.FW
@@ -0,0 +1,99 @@
+#!/sbin/ipf -f -
+#
+# SAMPLE: RESTRICTIVE FILTER RULES
+#
+# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3
+#
+# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32
+#
+# ed0 - (internal) network interface, address w.x.y.z/32
+#
+# This file contains the basic rules needed to construct a firewall for the
+# above situation.
+#
+#-------------------------------------------------------
+# *Nasty* packets we don't want to allow near us at all!
+# short packets which are packets fragmented too short to be real.
+block in log quick all with short
+#-------------------------------------------------------
+# Group setup.
+# ============
+# By default, block and log everything. This maybe too much logging
+# (especially for ed0) and needs to be further refined.
+#
+block in log on ppp0 all head 100
+block in log proto tcp all flags S/SA head 101 group 100
+block out log on ppp0 all head 150
+block in log on ed0 from w.x.y.z/24 to any head 200
+block in log proto tcp all flags S/SA head 201 group 200
+block in log proto udp all head 202 group 200
+block out log on ed0 all head 250
+#-------------------------------------------------------
+# Localhost packets.
+# ==================
+# packets going in/out of network interfaces that aren't on the loopback
+# interface should *NOT* exist.
+block in log quick from 127.0.0.0/8 to any group 100
+block in log quick from any to 127.0.0.0/8 group 100
+block in log quick from 127.0.0.0/8 to any group 200
+block in log quick from any to 127.0.0.0/8 group 200
+# And of course, make sure the loopback allows packets to traverse it.
+pass in quick on lo0 all
+pass out quick on lo0 all
+#-------------------------------------------------------
+# Invalid Internet packets.
+# =========================
+#
+# Deny reserved addresses.
+#
+block in log quick from 10.0.0.0/8 to any group 100
+block in log quick from 192.168.0.0/16 to any group 100
+block in log quick from 172.16.0.0/12 to any group 100
+#
+# Prevent IP spoofing.
+#
+block in log quick from a.b.c.d/24 to any group 100
+#
+#-------------------------------------------------------
+# Allow outgoing DNS requests (no named on firewall)
+#
+pass in quick proto udp from any to any port = 53 keep state group 202
+#
+# If we were running named on the firewall and all internal hosts talked to
+# it, we'd use the following:
+#
+#pass in quick proto udp from any to w.x.y.z/32 port = 53 keep state group 202
+#pass out quick on ppp0 proto udp from a.b.c.d/32 to any port = 53 keep state
+#
+# Allow outgoing FTP from any internal host to any external FTP server.
+#
+pass in quick proto tcp from any to any port = ftp keep state group 201
+pass in quick proto tcp from any to any port = ftp-data keep state group 201
+pass in quick proto tcp from any port = ftp-data to any port > 1023 keep state group 101
+#
+# Allow NTP from any internal host to any external NTP server.
+#
+pass in quick proto udp from any to any port = ntp keep state group 202
+#
+# Allow outgoing connections: SSH, TELNET, WWW
+#
+pass in quick proto tcp from any to any port = 22 keep state group 201
+pass in quick proto tcp from any to any port = telnet keep state group 201
+pass in quick proto tcp from any to any port = www keep state group 201
+#
+#-------------------------------------------------------
+block in log proto tcp from any to a.b.c.d/32 flags S/SA head 110 group 100
+#
+# Allow incoming to the external firewall interface: mail, WWW, DNS
+#
+pass in log quick proto tcp from any to any port = smtp keep state group 110
+pass in log quick proto tcp from any to any port = www keep state group 110
+pass in log quick proto tcp from any to any port = 53 keep state group 110
+pass in log quick proto udp from any to any port = 53 keep state group 100
+#-------------------------------------------------------
+# Log these:
+# ==========
+# * return RST packets for invalid SYN packets to help the other end close
+block return-rst in log proto tcp from any to any flags S/SA group 100
+# * return ICMP error packets for invalid UDP packets
+block return-icmp(net-unr) in proto udp all group 100
diff --git a/share/examples/ipfilter/rules/BASIC_2.FW b/share/examples/ipfilter/rules/BASIC_2.FW
new file mode 100644
index 000000000000..1d4fd7317673
--- /dev/null
+++ b/share/examples/ipfilter/rules/BASIC_2.FW
@@ -0,0 +1,72 @@
+#!/sbin/ipf -f -
+#
+# SAMPLE: PERMISSIVE FILTER RULES
+#
+# THIS EXAMPLE IS WRITTEN FOR IP FILTER 3.3
+#
+# ppp0 - (external) PPP connection to ISP, address a.b.c.d/32
+#
+# ed0 - (internal) network interface, address w.x.y.z/32
+#
+# This file contains the basic rules needed to construct a firewall for the
+# above situation.
+#
+#-------------------------------------------------------
+# *Nasty* packets we don't want to allow near us at all!
+# short packets which are packets fragmented too short to be real.
+block in log quick all with short
+#-------------------------------------------------------
+# Group setup.
+# ============
+# By default, block and log everything. This maybe too much logging
+# (especially for ed0) and needs to be further refined.
+#
+block in log on ppp0 all head 100
+block out log on ppp0 all head 150
+block in log on ed0 from w.x.y.z/24 to any head 200
+block out log on ed0 all head 250
+#-------------------------------------------------------
+# Invalid Internet packets.
+# =========================
+#
+# Deny reserved addresses.
+#
+block in log quick from 10.0.0.0/8 to any group 100
+block in log quick from 192.168.0.0/16 to any group 100
+block in log quick from 172.16.0.0/12 to any group 100
+#
+# Prevent IP spoofing.
+#
+block in log quick from a.b.c.d/24 to any group 100
+#
+#-------------------------------------------------------
+# Localhost packets.
+# ==================
+# packets going in/out of network interfaces that aren't on the loopback
+# interface should *NOT* exist.
+block in log quick from 127.0.0.0/8 to any group 100
+block in log quick from any to 127.0.0.0/8 group 100
+block in log quick from 127.0.0.0/8 to any group 200
+block in log quick from any to 127.0.0.0/8 group 200
+# And of course, make sure the loopback allows packets to traverse it.
+pass in quick on lo0 all
+pass out quick on lo0 all
+#-------------------------------------------------------
+# Allow any communication between the inside network and the outside only.
+#
+# Allow all outgoing connections (SSH, TELNET, FTP, WWW, gopher, etc)
+#
+pass in log quick proto tcp all flags S/SA keep state group 200
+#
+# Support all UDP `connections' initiated from inside.
+#
+# Allow ping out
+#
+pass in log quick proto icmp all keep state group 200
+#-------------------------------------------------------
+# Log these:
+# ==========
+# * return RST packets for invalid SYN packets to help the other end close
+block return-rst in log proto tcp from any to any flags S/SA group 100
+# * return ICMP error packets for invalid UDP packets
+block return-icmp(net-unr) in proto udp all group 100
diff --git a/share/examples/ipfilter/rules/example.1 b/share/examples/ipfilter/rules/example.1
new file mode 100644
index 000000000000..ff93f492cafe
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.1
@@ -0,0 +1,4 @@
+#
+# block all incoming TCP packets on le0 from host 10.1.1.1 to any destination.
+#
+block in on le0 proto tcp from 10.1.1.1/32 to any
diff --git a/share/examples/ipfilter/rules/example.10 b/share/examples/ipfilter/rules/example.10
new file mode 100644
index 000000000000..560d1e670f61
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.10
@@ -0,0 +1,12 @@
+#
+# pass ack packets (ie established connection)
+#
+pass in proto tcp from 10.1.0.0/16 port = 23 to 10.2.0.0/16 flags A/A
+pass out proto tcp from 10.1.0.0/16 port = 23 to 10.2.0.0/16 flags A/A
+#
+# block incoming connection requests to my internal network from the big bad
+# internet.
+#
+block in on le0 proto tcp from any to 10.1.0.0/16 flags S/SA
+# to block the replies:
+block out on le0 proto tcp from 10.1.0.0 to any flags SA/SA
diff --git a/share/examples/ipfilter/rules/example.11 b/share/examples/ipfilter/rules/example.11
new file mode 100644
index 000000000000..c6b4e7ff0d73
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.11
@@ -0,0 +1,26 @@
+#
+# allow any TCP packets from the same subnet as foo is on through to host
+# 10.1.1.2 if they are destined for port 6667.
+#
+pass in proto tcp from 10.2.2.2/24 to 10.1.1.2/32 port = 6667
+#
+# allow in UDP packets which are NOT from port 53 and are destined for
+# localhost
+#
+pass in proto udp from 10.2.2.2 port != 53 to localhost
+#
+# block anything trying to get to X terminal ports, X:0 to X:9
+#
+block in proto tcp from any to any port 5999 >< 6010
+#
+# allow any connections to be made, except to BSD print/r-services
+# this will also protect syslog.
+#
+block in proto tcp/udp all
+pass in proto tcp/udp from any to any port 512 <> 515
+#
+# allow any connections to be made, except to BSD print/r-services
+# this will also protect syslog.
+#
+pass in proto tcp/udp all
+block in proto tcp/udp from any to any port 511 >< 516
diff --git a/share/examples/ipfilter/rules/example.12 b/share/examples/ipfilter/rules/example.12
new file mode 100644
index 000000000000..c0ba1d3cdda1
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.12
@@ -0,0 +1,17 @@
+#
+# get rid of all short IP fragments (too small for valid comparison)
+#
+block in proto tcp all with short
+#
+# drop and log any IP packets with options set in them.
+#
+block in log all with ipopts
+#
+# log packets with BOTH ssrr and lsrr set
+#
+log in all with opt lsrr,ssrr
+#
+# drop any source routing options
+#
+block in quick all with opt lsrr
+block in quick all with opt ssrr
diff --git a/share/examples/ipfilter/rules/example.13 b/share/examples/ipfilter/rules/example.13
new file mode 100644
index 000000000000..854f07f1694f
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.13
@@ -0,0 +1,17 @@
+#
+# Log all short TCP packets to qe3, with 10.3.3.3 as the intended
+# destination for the packet.
+#
+block in on qe0 to qe3:10.3.3.3 proto tcp all with short
+#
+# Log all connection attempts for TCP
+#
+pass in on le0 dup-to le1:10.3.3.3 proto tcp all flags S/SA
+#
+# Route all UDP packets through transparently.
+#
+pass in on ppp0 fastroute proto udp all
+#
+# Route all ICMP packets to network 10 out through le1, to 10.3.3.1
+#
+pass in on le0 to le1:10.3.3.1 proto icmp all
diff --git a/share/examples/ipfilter/rules/example.2 b/share/examples/ipfilter/rules/example.2
new file mode 100644
index 000000000000..4f81725eeb0c
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.2
@@ -0,0 +1,5 @@
+#
+# block all outgoing TCP packets on le0 from any host to port 23 of
+# host 10.1.1.2
+#
+block out on le0 proto tcp from any to 10.1.1.3/32 port = 23
diff --git a/share/examples/ipfilter/rules/example.3 b/share/examples/ipfilter/rules/example.3
new file mode 100644
index 000000000000..cd31f73e7c2b
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.3
@@ -0,0 +1,40 @@
+#
+# block all inbound packets.
+#
+block in from any to any
+#
+# pass through packets to and from localhost.
+#
+pass in from 127.0.0.1/32 to 127.0.0.1/32
+#
+# allow a variety of individual hosts to send any type of IP packet to any
+# other host.
+#
+pass in from 10.1.3.1/32 to any
+pass in from 10.1.3.2/32 to any
+pass in from 10.1.3.3/32 to any
+pass in from 10.1.3.4/32 to any
+pass in from 10.1.3.5/32 to any
+pass in from 10.1.0.13/32 to any
+pass in from 10.1.1.1/32 to any
+pass in from 10.1.2.1/32 to any
+#
+#
+# block all outbound packets.
+#
+block out from any to any
+#
+# allow any packets destined for localhost out.
+#
+pass out from any to 127.0.0.1/32
+#
+# allow any host to send any IP packet out to a limited number of hosts.
+#
+pass out from any to 10.1.3.1/32
+pass out from any to 10.1.3.2/32
+pass out from any to 10.1.3.3/32
+pass out from any to 10.1.3.4/32
+pass out from any to 10.1.3.5/32
+pass out from any to 10.1.0.13/32
+pass out from any to 10.1.1.1/32
+pass out from any to 10.1.2.1/32
diff --git a/share/examples/ipfilter/rules/example.4 b/share/examples/ipfilter/rules/example.4
new file mode 100644
index 000000000000..7918ec2fbd99
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.4
@@ -0,0 +1,4 @@
+#
+# block all ICMP packets.
+#
+block in proto icmp from any to any
diff --git a/share/examples/ipfilter/rules/example.5 b/share/examples/ipfilter/rules/example.5
new file mode 100644
index 000000000000..6d688b5eab80
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.5
@@ -0,0 +1,25 @@
+#
+# test ruleset
+#
+# allow packets coming from foo to bar through.
+#
+pass in from 10.1.1.2 to 10.2.1.1
+#
+# allow any TCP packets from the same subnet as foo is on through to host
+# 10.1.1.2 if they are destined for port 6667.
+#
+pass in proto tcp from 10.2.2.2/24 to 10.1.1.2/32 port = 6667
+#
+# allow in UDP packets which are NOT from port 53 and are destined for
+# localhost
+#
+pass in proto udp from 10.2.2.2 port != 53 to localhost
+#
+# block all ICMP unreachables.
+#
+block in proto icmp from any to any icmp-type unreach
+#
+# allow packets through which have a non-standard IP header length (ie there
+# are IP options such as source-routing present).
+#
+pass in from any to any with ipopts
diff --git a/share/examples/ipfilter/rules/example.6 b/share/examples/ipfilter/rules/example.6
new file mode 100644
index 000000000000..d40f0f3d2a18
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.6
@@ -0,0 +1,5 @@
+#
+# block all TCP packets with only the SYN flag set (this is the first
+# packet sent to establish a connection) out of the SYN-ACK pair.
+#
+block in proto tcp from any to any flags S/SA
diff --git a/share/examples/ipfilter/rules/example.7 b/share/examples/ipfilter/rules/example.7
new file mode 100644
index 000000000000..062de9811935
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.7
@@ -0,0 +1,12 @@
+# block all ICMP packets.
+#
+block in proto icmp all
+#
+# allow in ICMP echos and echo-replies.
+#
+pass in on le1 proto icmp from any to any icmp-type echo
+pass in on le1 proto icmp from any to any icmp-type echorep
+#
+# block all ICMP destination unreachable packets which are port-unreachables
+#
+block in on le1 proto icmp from any to any icmp-type unreach code 3
diff --git a/share/examples/ipfilter/rules/example.8 b/share/examples/ipfilter/rules/example.8
new file mode 100644
index 000000000000..baa02581256e
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.8
@@ -0,0 +1,10 @@
+#
+# block all incoming TCP connections but send back a TCP-RST for ones to
+# the ident port
+#
+block in proto tcp from any to any flags S/SA
+block return-rst in quick proto tcp from any to any port = 113 flags S/SA
+#
+# block all inbound UDP packets and send back an ICMP error.
+#
+block return-icmp in proto udp from any to any
diff --git a/share/examples/ipfilter/rules/example.9 b/share/examples/ipfilter/rules/example.9
new file mode 100644
index 000000000000..daff2031db8e
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.9
@@ -0,0 +1,12 @@
+#
+# drop all packets without IP security options
+#
+block in all
+pass in all with opt sec
+#
+# only allow packets in and out on le1 which are top secret
+#
+block out on le1 all
+pass out on le1 all with opt sec-class topsecret
+block in on le1 all
+pass in on le1 all with opt sec-class topsecret
diff --git a/share/examples/ipfilter/rules/example.sr b/share/examples/ipfilter/rules/example.sr
new file mode 100644
index 000000000000..c4c1994030ba
--- /dev/null
+++ b/share/examples/ipfilter/rules/example.sr
@@ -0,0 +1,61 @@
+#
+# log all inbound packet on le0 which has IP options present
+#
+log in on le0 from any to any with ipopts
+#
+# block any inbound packets on le0 which are fragmented and "too short" to
+# do any meaningful comparison on. This actually only applies to TCP
+# packets which can be missing the flags/ports (depending on which part
+# of the fragment you see).
+#
+block in log quick on le0 from any to any with short frag
+#
+# log all inbound TCP packets with the SYN flag (only) set
+# (NOTE: if it were an inbound TCP packet with the SYN flag set and it
+# had IP options present, this rule and the above would cause it
+# to be logged twice).
+#
+log in on le0 proto tcp from any to any flags S/SA
+#
+# block and log any inbound ICMP unreachables
+#
+block in log on le0 proto icmp from any to any icmp-type unreach
+#
+# block and log any inbound UDP packets on le0 which are going to port 2049
+# (the NFS port).
+#
+block in log on le0 proto udp from any to any port = 2049
+#
+# quickly allow any packets to/from a particular pair of hosts
+#
+pass in quick from any to 10.1.3.2/32
+pass in quick from any to 10.1.0.13/32
+pass in quick from 10.1.3.2/32 to any
+pass in quick from 10.1.0.13/32 to any
+#
+# block (and stop matching) any packet with IP options present.
+#
+block in quick on le0 from any to any with ipopts
+#
+# allow any packet through
+#
+pass in from any to any
+#
+# block any inbound UDP packets destined for these subnets.
+#
+block in on le0 proto udp from any to 10.1.3.0/24
+block in on le0 proto udp from any to 10.1.1.0/24
+block in on le0 proto udp from any to 10.1.2.0/24
+#
+# block any inbound TCP packets with only the SYN flag set that are
+# destined for these subnets.
+#
+block in on le0 proto tcp from any to 10.1.3.0/24 flags S/SA
+block in on le0 proto tcp from any to 10.1.2.0/24 flags S/SA
+block in on le0 proto tcp from any to 10.1.1.0/24 flags S/SA
+#
+# block any inbound ICMP packets destined for these subnets.
+#
+block in on le0 proto icmp from any to 10.1.3.0/24
+block in on le0 proto icmp from any to 10.1.1.0/24
+block in on le0 proto icmp from any to 10.1.2.0/24
diff --git a/share/examples/ipfilter/rules/firewall b/share/examples/ipfilter/rules/firewall
new file mode 100644
index 000000000000..f26b7150b98c
--- /dev/null
+++ b/share/examples/ipfilter/rules/firewall
@@ -0,0 +1,39 @@
+Configuring IP Filter for firewall usage.
+=========================================
+
+Step 1 - Block out "bad" IP packets.
+------------------------------------
+
+Run the perl script "mkfilters". This will generate a list of blocking
+rules which:
+ a) blocks all packets which might belong to an IP Spoofing attack;
+ b) blocks all packets with IP options;
+ c) blocks all packets which have a length which is too short for
+ any legal packet;
+
+Step 2 - Convert Network Security Policy to filter rules.
+---------------------------------------------------------
+
+Draw up a list of which services you want to allow users to use on the
+Internet (e.g. WWW, ftp, etc). Draw up a separate list for what you
+want each host that is part of your firewall to be allowed to do, including
+communication with internal hosts.
+
+Step 3 - Create TCP "keep state" rules.
+---------------------------------------
+
+For each service that uses TCP, create a rule as follows:
+
+pass in on <int-a> proto tcp from <int-net> to any port <ext-service> flags S/SA keep state
+
+where
+* "int-a" is the internal interface of the firewall. That is, it is the
+ closest to your internal network in terms of network hops.
+
+* "int-net" is the internal network IP# subnet address range. This might
+ be something like 10.1.0.0/16, or 128.33.1.0/24
+
+* "ext-service" is the service to which you wish to connect or if it doesn't
+ have a proper name, a number can be used. The translation of "ext-service"
+ as a name to a number is controlled with the /etc/services file.
+
diff --git a/share/examples/ipfilter/rules/ftp-proxy b/share/examples/ipfilter/rules/ftp-proxy
new file mode 100644
index 000000000000..ad2f7171e85a
--- /dev/null
+++ b/share/examples/ipfilter/rules/ftp-proxy
@@ -0,0 +1,45 @@
+How to setup FTP proxying using the built in proxy code.
+========================================================
+
+NOTE: Currently, the built-in FTP proxy is only available for use with NAT
+ (i.e. only if you're already using "map" rules with ipnat). It does
+ support null-NAT mappings, that is, using the proxy without changing
+ the addresses.
+
+Lets assume your network diagram looks something like this:
+
+
+[host A]
+ |a
+---+-------------+----------
+ |b
+ [host B]
+ |c
+---+-------------+----------
+ |d
+[host C]
+
+and IP Filter is running on host B. If you want to proxy FTP from A to C
+then you would do:
+
+map int-c ipaddr-a/32 -> ip-addr-c-net/32 proxy port ftp ftp/tcp
+
+int-c = name of "interface c"
+ipaddr-a = ip# of interface a
+ipaddr-c-net = another ip# on the C-network (usually not the same as the
+interface).
+
+e.g., if host A was 10.1.1.1, host B had two network interfaces ed0 and vx0
+which had IP#'s 10.1.1.2 and 203.45.67.89 respectively, and host C was
+203.45.67.90, you would do:
+
+map vx0 10.1.1.1/32 -> 203.45.67.91/32 proxy port ftp ftp/tcp
+
+where:
+ipaddr-a = 10.1.1.1
+int-c = vx0
+ipaddr-c-net = 203.45.67.91
+
+The "map" rule for this proxy should precede any other NAT rules you are
+using.
+
diff --git a/share/examples/ipfilter/rules/ftppxy b/share/examples/ipfilter/rules/ftppxy
new file mode 100755
index 000000000000..2c42c527fa1e
--- /dev/null
+++ b/share/examples/ipfilter/rules/ftppxy
@@ -0,0 +1,6 @@
+#!/bin/sh
+# The proxy bit is as follows:
+# proxy [port <portname>] <tag>/<protocol>
+# the <tag> should match a tagname in the proxy table, as does the protocol.
+# this format isn't finalised yet
+echo "map ed0 0/0 -> 192.1.1.1/32 proxy port ftp ftp/tcp" | /sbin/ipnat -f -
diff --git a/share/examples/ipfilter/rules/ip_rules b/share/examples/ipfilter/rules/ip_rules
new file mode 100644
index 000000000000..9850f16b9306
--- /dev/null
+++ b/share/examples/ipfilter/rules/ip_rules
@@ -0,0 +1,3 @@
+# Used to generate ../ip_rules.c and ../ip_rules.h
+pass in all
+pass out all
diff --git a/share/examples/ipfilter/rules/ipmon.conf b/share/examples/ipfilter/rules/ipmon.conf
new file mode 100644
index 000000000000..652afceb3ea1
--- /dev/null
+++ b/share/examples/ipfilter/rules/ipmon.conf
@@ -0,0 +1,25 @@
+#
+#
+#
+#
+match { logtag = 10000; }
+do { execute("/usr/bin/mail -s 'logtag 10000' root"); };
+#
+match { logtag = 2000, every 10 seconds; }
+do { execute("echo 'XXXXXXXX tag 2000 packet XXXXXXXX'"); };
+#
+match { protocol = udp, result = block; }
+do { file("file:///var/log/udp-block"); };
+#
+match { protocol = tcp, result = block, dstport = 25; }
+do { syslog("local0.info"), syslog("local1."), syslog(".warn"); };
+#
+match { srcip = 10.1.0.0/16, dstip = 192.168.1.0/24; }
+do { execute("/usr/bin/mail -s 'from 10.1 to 192.168.1' root"); };
+
+#
+match {
+ rule = 12, logtag = 101, direction = in, result = block,
+ protocol = udp, srcip = 10.1.0.0/16, dstip = 192.168.1.0/24; }
+do { nothing; };
+#
diff --git a/share/examples/ipfilter/rules/nat-setup b/share/examples/ipfilter/rules/nat-setup
new file mode 100644
index 000000000000..b10e8f113e0c
--- /dev/null
+++ b/share/examples/ipfilter/rules/nat-setup
@@ -0,0 +1,77 @@
+Configuring NAT on your network.
+================================
+
+To start setting up NAT, we need to define which is your "internal" interface
+and which is your "external" interface. The "internal" interface is the
+network adapter connected to the network with private IP addresses which
+you need to change for communicating on the Internet. The "external"
+interface is configured with a valid internet address.
+
+For example, your internal interface might have an IP# of 10.1.1.1 and be
+connected to your ethernet, whilst your external interface might be a PPP
+connection with an IP number of 204.51.62.176.
+
+Thus your network might look like this:
+
+<Internal Network>
+ [pc] [pc]
+ | |
++-+---------+------+
+ |
+ [firewall]
+ |
+ |
+ Internet
+<External Network>
+
+
+Writing the map-rule.
+---------------------
+When you're connected to the Internet, you will either have a block of IP
+addresses assigned to you, maybe several different blocks, or you use a
+single IP address, i.e. with dialup PPP. If you have a block of addresses
+assigned, these can be used to create either a 1:1 mapping (if you have
+only a few internal IP addresses) or N:1 mappings, where groups of internal
+addresses map to a single IP address and unless you have enough Internet
+addresses for a 1:1 mapping, you will want to do "portmapping" for TCP and
+UDP port numbers.
+
+For an N:1 situation, you might have:
+
+map ppp0 10.1.0.0/16 -> 209.23.1.5/32 portmap tcp/udp 10000:40000
+map ppp0 10.1.0.0/16 -> 209.23.1.5/32 portmap
+
+where if you had 16 addresses available, you could do:
+
+map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap tcp/udp 10000:40000
+map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap
+
+Or if you wanted to allocate subnets to each IP#, you might do:
+
+map ppp0 10.1.1.0/24 -> 209.23.1.2/32 portmap tcp/udp 10000:40000
+map ppp0 10.1.2.0/24 -> 209.23.1.3/32 portmap tcp/udp 10000:40000
+map ppp0 10.1.3.0/24 -> 209.23.1.4/32 portmap tcp/udp 10000:40000
+map ppp0 10.1.1.0/24 -> 209.23.1.2/32 portmap
+map ppp0 10.1.2.0/24 -> 209.23.1.3/32 portmap
+map ppp0 10.1.3.0/24 -> 209.23.1.4/32 portmap
+
+*** NOTE: NAT rules are used on a first-match basis only!
+
+
+Filtering with NAT.
+-------------------
+IP Filter will always translate addresses in a packet _BEFORE_ it checks its
+access list for inbound packets and translates addresses _AFTER_ it has
+checked the access control lists for outbound packets.
+
+For example (using the above NAT rules), if you wanted to prevent all hosts
+in the 10.1.2.0/24 subnet from using NAT, you might use the following rule
+with ipf:
+
+block out on ppp0 from 10.1.2.0/24 to any
+block in on ppp0 from any to 10.1.2.0/24
+
+and use these with ipnat:
+
+map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap tcp/udp 10000:40000
+map ppp0 10.1.0.0/16 -> 209.23.1.0/28 portmap
diff --git a/share/examples/ipfilter/rules/nat.eg b/share/examples/ipfilter/rules/nat.eg
new file mode 100644
index 000000000000..9c26754a57fa
--- /dev/null
+++ b/share/examples/ipfilter/rules/nat.eg
@@ -0,0 +1,14 @@
+# map all tcp connections from 10.1.0.0/16 to 240.1.0.1, changing the source
+# port number to something between 10,000 and 20,000 inclusive. For all other
+# IP packets, allocate an IP # between 240.1.0.0 and 240.1.0.255, temporarily
+# for each new user.
+#
+map ed1 10.1.0.0/16 -> 240.1.0.1/32 portmap tcp 10000:20000
+map ed1 10.1.0.0/16 -> 240.1.0.0/24
+#
+# Redirection is triggered for input packets.
+# For example, to redirect FTP connections through this box, to the local ftp
+# port, forcing them to connect through a proxy, you would use:
+#
+rdr ed0 0.0.0.0/0 port ftp -> 127.0.0.1 port ftp
+#
diff --git a/share/examples/ipfilter/rules/pool.conf b/share/examples/ipfilter/rules/pool.conf
new file mode 100644
index 000000000000..285398ddf3b1
--- /dev/null
+++ b/share/examples/ipfilter/rules/pool.conf
@@ -0,0 +1,4 @@
+#
+pool 0 = { !10.0.0.0 - 10.255.255.255, 10.1.0.0 - 10.1.255.255,
+ 10.1.1.0 - 10.1.1.255, !10.1.2.0 - 10.2.2.255,
+ 10.1.2.3 - 10.1.2.3, 10.1.2.15 - 10.1.2.15 };
diff --git a/share/examples/ipfilter/rules/server b/share/examples/ipfilter/rules/server
new file mode 100644
index 000000000000..de0e9bbd06d8
--- /dev/null
+++ b/share/examples/ipfilter/rules/server
@@ -0,0 +1,11 @@
+#
+# For a network server, which has two interfaces, 128.1.40.1 (le0) and
+# 128.1.2.1 (le1), we want to block all IP spoofing attacks. le1 is
+# connected to the majority of the network, whilst le0 is connected to a
+# leaf subnet. We're not concerned about filtering individual services
+# or
+#
+pass in quick on le0 from 128.1.40.0/24 to any
+block in log quick on le0 from any to any
+block in log quick on le1 from 128.1.1.0/24 to any
+pass in quick on le1 from any to any
diff --git a/share/examples/ipfilter/rules/tcpstate b/share/examples/ipfilter/rules/tcpstate
new file mode 100644
index 000000000000..339a25f963fc
--- /dev/null
+++ b/share/examples/ipfilter/rules/tcpstate
@@ -0,0 +1,13 @@
+#
+# Only allow TCP packets in/out of le0 if there is an outgoing connection setup
+# somewhere, waiting for it.
+#
+pass out quick on le0 proto tcp from any to any flags S/SAFR keep state
+block out on le0 proto tcp all
+block in on le0 proto tcp all
+#
+# allow nameserver queries and replies to pass through, but no other UDP
+#
+pass out quick on le0 proto udp from any to any port = 53 keep state
+block out on le0 proto udp all
+block in on le0 proto udp all
diff --git a/share/examples/ipfilter/samples/Makefile b/share/examples/ipfilter/samples/Makefile
new file mode 100644
index 000000000000..47ab4a26d5c0
--- /dev/null
+++ b/share/examples/ipfilter/samples/Makefile
@@ -0,0 +1,24 @@
+CC=gcc
+all:
+ @echo "Please do one of the following:"
+ @echo "make bsd"
+ @echo "make bsdi"
+ @echo "make freebsd"
+ @echo "make freebsd22"
+ @echo "make netbsd"
+ @echo "make openbsd"
+ @echo "make sunos4"
+ @echo "make sunos5"
+
+sunos5:
+ $(CC) -I.. userauth.c -o userauth -lsocket -lnsl
+ $(CC) -I.. proxy.c -o proxy -lsocket -lnsl
+ $(CC) -I.. relay.c -o relay -lsocket -lnsl
+
+freebsd freebsd22 netbsd bsd bsdi sunos4 openbsd:
+ $(CC) -I.. userauth.c -o userauth
+ $(CC) -I.. proxy.c -o proxy
+ $(CC) -I.. relay.c -o relay
+
+clean:
+ /bin/rm -f userauth proxy relay
diff --git a/share/examples/ipfilter/samples/ipfilter-pb.gif b/share/examples/ipfilter/samples/ipfilter-pb.gif
new file mode 100644
index 000000000000..afaefa866541
--- /dev/null
+++ b/share/examples/ipfilter/samples/ipfilter-pb.gif
Binary files differ
diff --git a/share/examples/ipfilter/samples/proxy.c b/share/examples/ipfilter/samples/proxy.c
new file mode 100644
index 000000000000..7f5949b519be
--- /dev/null
+++ b/share/examples/ipfilter/samples/proxy.c
@@ -0,0 +1,316 @@
+
+/*
+ * Sample transparent proxy program.
+ *
+ * Sample implementation of a program which intercepts a TCP connectiona and
+ * just echos all data back to the origin. Written to work via inetd as a
+ * "nonwait" program running as root; ie.
+ * tcpmux stream tcp nowait root /usr/local/bin/proxy proxy
+ * with a NAT rue like this:
+ * rdr smc0 0/0 port 80 -> 127.0.0.1/32 port 1
+ */
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <syslog.h>
+#if !defined(__SVR4) && !defined(__svr4__)
+#include <strings.h>
+#else
+#include <sys/byteorder.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#if defined(sun) && (defined(__svr4__) || defined(__SVR4))
+# include <sys/ioccom.h>
+# include <sys/sysmacros.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <ctype.h>
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ip_state.h"
+#include "netinet/ip_proxy.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ipl.h"
+
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct sockaddr_in sin, sloc, sout;
+ ipfobj_t obj;
+ natlookup_t natlook;
+ char buffer[512];
+ int namelen, fd, n;
+
+ /*
+ * get IP# and port # of the remote end of the connection (at the
+ * origin).
+ */
+ namelen = sizeof(sin);
+ if (getpeername(0, (struct sockaddr *)&sin, &namelen) == -1) {
+ perror("getpeername");
+ exit(-1);
+ }
+
+ /*
+ * get IP# and port # of the local end of the connection (at the
+ * man-in-the-middle).
+ */
+ namelen = sizeof(sin);
+ if (getsockname(0, (struct sockaddr *)&sloc, &namelen) == -1) {
+ perror("getsockname");
+ exit(-1);
+ }
+
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(natlook);
+ obj.ipfo_ptr = &natlook;
+ obj.ipfo_type = IPFOBJ_NATLOOKUP;
+
+ /*
+ * Build up the NAT natlookup structure.
+ */
+ bzero((char *)&natlook, sizeof(natlook));
+ natlook.nl_outip = sin.sin_addr;
+ natlook.nl_inip = sloc.sin_addr;
+ natlook.nl_flags = IPN_TCP;
+ natlook.nl_outport = sin.sin_port;
+ natlook.nl_inport = sloc.sin_port;
+
+ /*
+ * Open the NAT device and lookup the mapping pair.
+ */
+ fd = open(IPNAT_NAME, O_RDONLY);
+ if (ioctl(fd, SIOCGNATL, &obj) == -1) {
+ perror("ioctl(SIOCGNATL)");
+ exit(-1);
+ }
+
+#define DO_NAT_OUT
+#ifdef DO_NAT_OUT
+ if (argc > 1)
+ do_nat_out(0, 1, fd, &natlook, argv[1]);
+#else
+
+ /*
+ * Log it
+ */
+ syslog(LOG_DAEMON|LOG_INFO, "connect to %s,%d",
+ inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport));
+ printf("connect to %s,%d\n",
+ inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport));
+
+ /*
+ * Just echo data read in from stdin to stdout
+ */
+ while ((n = read(0, buffer, sizeof(buffer))) > 0)
+ if (write(1, buffer, n) != n)
+ break;
+ close(0);
+#endif
+}
+
+
+#ifdef DO_NAT_OUT
+do_nat_out(in, out, fd, nlp, extif)
+ int fd;
+ natlookup_t *nlp;
+ char *extif;
+{
+ nat_save_t ns, *nsp = &ns;
+ struct sockaddr_in usin;
+ u_32_t sum1, sum2, sumd;
+ int onoff, ofd, slen;
+ ipfobj_t obj;
+ ipnat_t *ipn;
+ nat_t *nat;
+
+ bzero((char *)&ns, sizeof(ns));
+
+ nat = &ns.ipn_nat;
+ nat->nat_p = IPPROTO_TCP;
+ nat->nat_dir = NAT_OUTBOUND;
+ if ((extif != NULL) && (*extif != '\0')) {
+ strncpy(nat->nat_ifnames[0], extif,
+ sizeof(nat->nat_ifnames[0]));
+ strncpy(nat->nat_ifnames[1], extif,
+ sizeof(nat->nat_ifnames[1]));
+ nat->nat_ifnames[0][sizeof(nat->nat_ifnames[0]) - 1] = '\0';
+ nat->nat_ifnames[1][sizeof(nat->nat_ifnames[1]) - 1] = '\0';
+ }
+
+ ofd = socket(AF_INET, SOCK_DGRAM, 0);
+ bzero((char *)&usin, sizeof(usin));
+ usin.sin_family = AF_INET;
+ usin.sin_addr = nlp->nl_realip;
+ usin.sin_port = nlp->nl_realport;
+ (void) connect(ofd, (struct sockaddr *)&usin, sizeof(usin));
+ slen = sizeof(usin);
+ (void) getsockname(ofd, (struct sockaddr *)&usin, &slen);
+ close(ofd);
+printf("local IP# to use: %s\n", inet_ntoa(usin.sin_addr));
+
+ if ((ofd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
+ perror("socket");
+ usin.sin_port = 0;
+ if (bind(ofd, (struct sockaddr *)&usin, sizeof(usin)))
+ perror("bind");
+ slen = sizeof(usin);
+ if (getsockname(ofd, (struct sockaddr *)&usin, &slen))
+ perror("getsockname");
+printf("local port# to use: %d\n", ntohs(usin.sin_port));
+
+ nat->nat_inip = usin.sin_addr;
+ nat->nat_outip = nlp->nl_outip;
+ nat->nat_oip = nlp->nl_realip;
+
+ sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)) + ntohs(usin.sin_port);
+ sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)) + ntohs(nlp->nl_outport);
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
+ nat->nat_sumd[1] = nat->nat_sumd[0];
+
+ sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr));
+ sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));
+ CALC_SUMD(sum1, sum2, sumd);
+ nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
+
+ nat->nat_inport = usin.sin_port;
+ nat->nat_outport = nlp->nl_outport;
+ nat->nat_oport = nlp->nl_realport;
+
+ nat->nat_flags = IPN_TCPUDP;
+
+ bzero((char *)&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(*nsp);
+ obj.ipfo_ptr = nsp;
+ obj.ipfo_type = IPFOBJ_NATSAVE;
+
+ onoff = 1;
+ if (ioctl(fd, SIOCSTLCK, &onoff) == 0) {
+ if (ioctl(fd, SIOCSTPUT, &obj) != 0)
+ perror("SIOCSTPUT");
+ onoff = 0;
+ if (ioctl(fd, SIOCSTLCK, &onoff) != 0)
+ perror("SIOCSTLCK");
+ }
+
+ usin.sin_addr = nlp->nl_realip;
+ usin.sin_port = nlp->nl_realport;
+printf("remote end for connection: %s,%d\n", inet_ntoa(usin.sin_addr),
+ntohs(usin.sin_port));
+fflush(stdout);
+ if (connect(ofd, (struct sockaddr *)&usin, sizeof(usin)))
+ perror("connect");
+
+ relay(in, out, ofd);
+}
+
+
+relay(in, out, net)
+ int in, out, net;
+{
+ char netbuf[1024], outbuf[1024];
+ char *nwptr, *nrptr, *owptr, *orptr;
+ size_t nsz, osz;
+ fd_set rd, wr;
+ int i, n, maxfd;
+
+ n = 0;
+ maxfd = in;
+ if (out > maxfd)
+ maxfd = out;
+ if (net > maxfd)
+ maxfd = net;
+
+ nrptr = netbuf;
+ nwptr = netbuf;
+ nsz = sizeof(netbuf);
+ orptr = outbuf;
+ owptr = outbuf;
+ osz = sizeof(outbuf);
+
+ while (n >= 0) {
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+
+ if (nrptr - netbuf < sizeof(netbuf))
+ FD_SET(in, &rd);
+ if (orptr - outbuf < sizeof(outbuf))
+ FD_SET(net, &rd);
+
+ if (nsz < sizeof(netbuf))
+ FD_SET(net, &wr);
+ if (osz < sizeof(outbuf))
+ FD_SET(out, &wr);
+
+ n = select(maxfd + 1, &rd, &wr, NULL, NULL);
+
+ if ((n > 0) && FD_ISSET(in, &rd)) {
+ i = read(in, nrptr, sizeof(netbuf) - (nrptr - netbuf));
+ if (i <= 0)
+ break;
+ nsz -= i;
+ nrptr += i;
+ n--;
+ }
+
+ if ((n > 0) && FD_ISSET(net, &rd)) {
+ i = read(net, orptr, sizeof(outbuf) - (orptr - outbuf));
+ if (i <= 0)
+ break;
+ osz -= i;
+ orptr += i;
+ n--;
+ }
+
+ if ((n > 0) && FD_ISSET(out, &wr)) {
+ i = write(out, owptr, orptr - owptr);
+ if (i <= 0)
+ break;
+ osz += i;
+ if (osz == sizeof(outbuf) || owptr == orptr) {
+ orptr = outbuf;
+ owptr = outbuf;
+ } else
+ owptr += i;
+ n--;
+ }
+
+ if ((n > 0) && FD_ISSET(net, &wr)) {
+ i = write(net, nwptr, nrptr - nwptr);
+ if (i <= 0)
+ break;
+ nsz += i;
+ if (nsz == sizeof(netbuf) || nwptr == nrptr) {
+ nrptr = netbuf;
+ nwptr = netbuf;
+ } else
+ nwptr += i;
+ }
+ }
+
+ close(net);
+ close(out);
+ close(in);
+}
+#endif
diff --git a/share/examples/ipfilter/samples/relay.c b/share/examples/ipfilter/samples/relay.c
new file mode 100644
index 000000000000..88d5fd968805
--- /dev/null
+++ b/share/examples/ipfilter/samples/relay.c
@@ -0,0 +1,195 @@
+
+/*
+ * Sample program to be used as a transparent proxy.
+ *
+ * Must be executed with permission enough to do an ioctl on /dev/ipl
+ * or equivalent. This is just a sample and is only alpha quality.
+ * - Darren Reed (8 April 1996)
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/syslog.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include "netinet/ip_compat.h"
+#include "netinet/ip_fil.h"
+#include "netinet/ip_nat.h"
+#include "netinet/ipl.h"
+
+#define RELAY_BUFSZ 8192
+
+char ibuff[RELAY_BUFSZ];
+char obuff[RELAY_BUFSZ];
+
+int relay(ifd, ofd, rfd)
+ int ifd, ofd, rfd;
+{
+ fd_set rfds, wfds;
+ char *irh, *irt, *rrh, *rrt;
+ char *iwh, *iwt, *rwh, *rwt;
+ int nfd, n, rw;
+
+ irh = irt = ibuff;
+ iwh = iwt = obuff;
+ nfd = ifd;
+ if (nfd < ofd)
+ nfd = ofd;
+ if (nfd < rfd)
+ nfd = rfd;
+
+ while (1) {
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ if (irh > irt)
+ FD_SET(rfd, &wfds);
+ if (irh < (ibuff + RELAY_BUFSZ))
+ FD_SET(ifd, &rfds);
+ if (iwh > iwt)
+ FD_SET(ofd, &wfds);
+ if (iwh < (obuff + RELAY_BUFSZ))
+ FD_SET(rfd, &rfds);
+
+ switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL)))
+ {
+ case -1 :
+ case 0 :
+ return(-1);
+ default :
+ if (FD_ISSET(ifd, &rfds)) {
+ rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh);
+ if (rw == -1)
+ return(-1);
+ if (rw == 0)
+ return(0);
+ irh += rw;
+ n--;
+ }
+ if (n && FD_ISSET(ofd, &wfds)) {
+ rw = write(ofd, iwt, iwh - iwt);
+ if (rw == -1)
+ return(-1);
+ iwt += rw;
+ n--;
+ }
+ if (n && FD_ISSET(rfd, &rfds)) {
+ rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh);
+ if (rw == -1)
+ return(-1);
+ if (rw == 0)
+ return(0);
+ iwh += rw;
+ n--;
+ }
+ if (n && FD_ISSET(rfd, &wfds)) {
+ rw = write(rfd, irt, irh - irt);
+ if (rw == -1)
+ return(-1);
+ irt += rw;
+ n--;
+ }
+ if (irh == irt)
+ irh = irt = ibuff;
+ if (iwh == iwt)
+ iwh = iwt = obuff;
+ }
+ }
+}
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct sockaddr_in sin;
+ ipfobj_t obj;
+ natlookup_t nl;
+ natlookup_t *nlp = &nl;
+ int fd, sl = sizeof(sl), se;
+
+ openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON);
+ if ((fd = open(IPNAT_NAME, O_RDONLY)) == -1) {
+ se = errno;
+ perror("open");
+ errno = se;
+ syslog(LOG_ERR, "open: %m\n");
+ exit(-1);
+ }
+
+ bzero(&obj, sizeof(obj));
+ obj.ipfo_rev = IPFILTER_VERSION;
+ obj.ipfo_size = sizeof(nl);
+ obj.ipfo_ptr = &nl;
+ obj.ipfo_type = IPFOBJ_NATLOOKUP;
+
+ bzero(&nl, sizeof(nl));
+ nl.nl_flags = IPN_TCP;
+
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sl = sizeof(sin);
+ if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) {
+ se = errno;
+ perror("getsockname");
+ errno = se;
+ syslog(LOG_ERR, "getsockname: %m\n");
+ exit(-1);
+ } else {
+ nl.nl_inip.s_addr = sin.sin_addr.s_addr;
+ nl.nl_inport = sin.sin_port;
+ }
+
+ bzero(&sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sl = sizeof(sin);
+ if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) {
+ se = errno;
+ perror("getpeername");
+ errno = se;
+ syslog(LOG_ERR, "getpeername: %m\n");
+ exit(-1);
+ } else {
+ nl.nl_outip.s_addr = sin.sin_addr.s_addr;
+ nl.nl_outport = sin.sin_port;
+ }
+
+ if (ioctl(fd, SIOCGNATL, &obj) == -1) {
+ se = errno;
+ perror("ioctl");
+ errno = se;
+ syslog(LOG_ERR, "ioctl: %m\n");
+ exit(-1);
+ }
+
+ sin.sin_port = nl.nl_realport;
+ sin.sin_addr = nl.nl_realip;
+ sl = sizeof(sin);
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (connect(fd, (struct sockaddr *)&sin, sl) == -1) {
+ se = errno;
+ perror("connect");
+ errno = se;
+ syslog(LOG_ERR, "connect: %m\n");
+ exit(-1);
+ }
+
+ (void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
+ (void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
+ (void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
+
+ syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr),
+ ntohs(sin.sin_port));
+ if (relay(0, 1, fd) == -1) {
+ se = errno;
+ perror("relay");
+ errno = se;
+ syslog(LOG_ERR, "relay: %m\n");
+ exit(-1);
+ }
+ exit(0);
+}
diff --git a/share/examples/ipfilter/samples/userauth.c b/share/examples/ipfilter/samples/userauth.c
new file mode 100644
index 000000000000..cc733a715322
--- /dev/null
+++ b/share/examples/ipfilter/samples/userauth.c
@@ -0,0 +1,61 @@
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include "ip_compat.h"
+#include "ip_fil.h"
+#include "ip_auth.h"
+
+extern int errno;
+
+main()
+{
+ struct frauth fra;
+ struct frauth *frap = &fra;
+ fr_info_t *fin = &fra.fra_info;
+ fr_ip_t *fi = &fin->fin_fi;
+ char yn[16];
+ int fd;
+
+ fd = open(IPL_NAME, O_RDWR);
+ fra.fra_len = 0;
+ fra.fra_buf = NULL;
+ while (ioctl(fd, SIOCAUTHW, &frap) == 0) {
+ if (fra.fra_info.fin_out)
+ fra.fra_pass = FR_OUTQUE;
+ else
+ fra.fra_pass = FR_INQUE;
+
+ printf("%s ", inet_ntoa(fi->fi_src));
+ if (fi->fi_flx & FI_TCPUDP)
+ printf("port %d ", fin->fin_data[0]);
+ printf("-> %s ", inet_ntoa(fi->fi_dst));
+ if (fi->fi_flx & FI_TCPUDP)
+ printf("port %d ", fin->fin_data[1]);
+ printf("\n");
+ printf("Allow packet through ? [y/n]");
+ fflush(stdout);
+ if (!fgets(yn, sizeof(yn), stdin))
+ break;
+ fflush(stdin);
+ if (yn[0] == 'n' || yn[0] == 'N')
+ fra.fra_pass |= FR_BLOCK;
+ else if (yn[0] == 'y' || yn[0] == 'Y') {
+ fra.fra_pass |= FR_PASS;
+ if (fra.fra_info.fin_fi.fi_flx & FI_TCPUDP)
+ fra.fra_pass |= FR_KEEPSTATE;
+ } else
+ fra.fra_pass |= FR_NOMATCH;
+ printf("answer = %c (%x), id %d idx %d\n", yn[0],
+ fra.fra_pass, fra.fra_info.fin_id, fra.fra_index);
+ if (ioctl(fd, SIOCAUTHR, &frap) != 0)
+ perror("SIOCAUTHR");
+ }
+ fprintf(stderr, "errno=%d \n", errno);
+ perror("frauth-SIOCAUTHW");
+}
diff --git a/share/examples/ipfw/change_rules.sh b/share/examples/ipfw/change_rules.sh
new file mode 100755
index 000000000000..469b6a6c2e71
--- /dev/null
+++ b/share/examples/ipfw/change_rules.sh
@@ -0,0 +1,154 @@
+#!/bin/sh
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2000 Alexandre Peixoto
+# 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.
+#
+
+# Change ipfw(8) rules with safety guarantees for remote operation
+#
+# Invoke this script to edit ${firewall_script}. It will call ${EDITOR},
+# or vi(1) if the environment variable is not set, for you to edit
+# ${firewall_script}, ask for confirmation, and then run
+# ${firewall_script}. You can then examine the output of ipfw list and
+# confirm whether you want the new version or not.
+#
+# If no answer is received in 30 seconds, the previous
+# ${firewall_script} is run, restoring the old rules (this assumes ipfw
+# flush is present in it).
+#
+# If the new rules are confirmed, they'll replace ${firewall_script} and
+# the previous ones will be copied to ${firewall_script}.{date}. Mail
+# will also be sent to root with a unified diff of the rule change.
+#
+# Unapproved rules are kept in ${firewall_script}.new, and you are
+# offered the option of changing them instead of the present rules when
+# you call this script.
+#
+# This script could be improved by using version control
+# software.
+
+if [ -r /etc/defaults/rc.conf ]; then
+ . /etc/defaults/rc.conf
+ source_rc_confs
+elif [ -r /etc/rc.conf ]; then
+ . /etc/rc.conf
+fi
+
+EDITOR=${EDITOR:-/usr/bin/vi}
+PAGER=${PAGER:-/usr/bin/more}
+
+tempfoo=`basename $0`
+TMPFILE=`mktemp -t ${tempfoo}` || exit 1
+
+get_yes_no() {
+ while true
+ do
+ echo -n "$1 (Y/N) ? "
+ read -t 30 a
+ if [ $? != 0 ]; then
+ a="No";
+ return;
+ fi
+ case $a in
+ [Yy]) a="Yes";
+ return;;
+ [Nn]) a="No";
+ return;;
+ *);;
+ esac
+ done
+}
+
+restore_rules() {
+ nohup sh ${firewall_script} </dev/null >/dev/null 2>&1
+ rm ${TMPFILE}
+ exit 1
+}
+
+case "${firewall_type}" in
+[Cc][Ll][Ii][Ee][Nn][Tt]|\
+[Cc][Ll][Oo][Ss][Ee][Dd]|\
+[Oo][Pp][Ee][Nn]|\
+[Ss][Ii][Mm][Pp][Ll][Ee]|\
+[Uu][Nn][Kk][Nn][Oo][Ww][Nn])
+ edit_file="${firewall_script}"
+ rules_edit=no
+ ;;
+*)
+ if [ -r "${firewall_type}" ]; then
+ edit_file="${firewall_type}"
+ rules_edit=yes
+ fi
+ ;;
+esac
+
+if [ -f ${edit_file}.new ]; then
+ get_yes_no "A new rules file already exists, do you want to use it"
+ [ $a = 'No' ] && cp ${edit_file} ${edit_file}.new
+else
+ cp ${edit_file} ${edit_file}.new
+fi
+
+trap restore_rules SIGHUP
+
+${EDITOR} ${edit_file}.new
+
+get_yes_no "Do you want to install the new rules"
+
+[ $a = 'No' ] && exit 1
+
+cat <<!
+The rules will be changed now. If the message 'Type y to keep the new
+rules' does not appear on the screen or the y key is not pressed in 30
+seconds, the original rules will be restored.
+The TCP/IP connections might be broken during the change. If so, restore
+the ssh/telnet connection being used.
+!
+
+if [ ${rules_edit} = yes ]; then
+ nohup sh ${firewall_script} ${firewall_type}.new \
+ < /dev/null > ${TMPFILE} 2>&1
+else
+ nohup sh ${firewall_script}.new \
+ < /dev/null > ${TMPFILE} 2>&1
+fi
+sleep 2;
+get_yes_no "Would you like to see the resulting new rules"
+[ $a = 'Yes' ] && ${PAGER} ${TMPFILE}
+get_yes_no "Type y to keep the new rules"
+[ $a != 'Yes' ] && restore_rules
+
+DATE=`date "+%Y%m%d%H%M"`
+cp ${edit_file} ${edit_file}.$DATE
+mv ${edit_file}.new ${edit_file}
+cat <<!
+The new rules are now installed. The previous rules have been preserved in
+the file ${edit_file}.$DATE
+!
+diff -u ${edit_file}.$DATE ${edit_file} \
+ | mail -s "`hostname` Firewall rule change" root
+rm ${TMPFILE}
+exit 0
diff --git a/share/examples/jails/README b/share/examples/jails/README
new file mode 100644
index 000000000000..9d4513ac87cc
--- /dev/null
+++ b/share/examples/jails/README
@@ -0,0 +1,66 @@
+
+The below 4 samples require a VIMAGE enabled kernel:
+
+ # (as root)
+ $ cp VIMAGE /usr/src/sys/amd64/conf/
+ $ cd /usr/src
+ $ make KERNCONF=VIMAGE kernel
+ $ reboot
+
+FreeBSD 12 has VIMAGE enabled in GENERIC on amd64.
+In that case, for jng simply load the ng_ether module first
+(ng_bridge and ng_eiface will load on demand):
+
+ # (as root)
+ # Load the ng_ether module at boot:
+ $ sysrc kld_list+=ng_ether
+ # Load ng_ether at once without rebooting:
+ $ kldload ng_ether
+
+Sample 1: jail.conf(5)
+
+ $ cp jib jng /usr/sbin/
+ $ cat jail.xxx.conf >> /etc/jail.conf
+ $ vi /etc/jail.conf
+ # NB: Customize root directory and bridge interface
+ $ sysrc jail_enable=YES
+ # NB: Assumes jail_list="" (meaning ``all jails in jail.conf'')
+ # NB: Assumes rc_conf_files="" (``below rc.conf(5) samples not used'')
+ $ service jail start
+
+Sample 2: rc.conf(5)
+
+ $ cp jib jng /usr/sbin/
+ $ cp rc.conf.jails /etc/
+ $ vi /etc/rc.conf.jails
+ # NB: Customize root directory and bridge interface
+ $ sysrc rc_conf_files+=/etc/rc.conf.jails
+ # NB: Assumes /etc/jail.conf does not exist and jail_list=""
+ $ service jail start
+
+Sample 3: Per-jail jail.conf(5)
+
+ $ cp jib jng /usr/sbin/
+ $ cp jail.xxx.conf /etc/
+ $ vi /etc/jail.xxx.conf
+ # NB: Customize root directory and bridge interface
+ $ sysrc jail_enable=YES
+ $ sysrc jail_list+=xxx
+ # NB: Assumes rc_conf_files=""
+ $ service jail start
+
+Sample 4: Per-jail rc.conf(5)
+
+ $ cp jib jng /usr/sbin/
+ $ cp rcjail.xxx.conf /etc/
+ $ vi /etc/rcjail.xxx.conf
+ # NB: Customize root directory and bridge interface
+ $ sysrc jail_enable=YES
+ $ sysrc jail_list+=xxx
+ $ sysrc rc_conf_files+=/etc/rcjail.xxx.conf
+ # NB: Assumes neither /etc/jail.conf nor /etc/jail.xxx.conf exist
+ $ service jail start
+
+For additional recipes, see share/examples/netgraph for
+making and hooking together jails using netgraph as the
+virtual networking fabric.
diff --git a/share/examples/jails/VIMAGE b/share/examples/jails/VIMAGE
new file mode 100644
index 000000000000..51e8a593c68e
--- /dev/null
+++ b/share/examples/jails/VIMAGE
@@ -0,0 +1,58 @@
+
+################################################################################
+######################### VIMAGE KERNEL CONFIGURATION ##########################
+################################################################################
+
+#################### Inheritance
+
+#
+# Inherit from, and override `GENERIC'
+#
+include GENERIC # Base configuration file
+ident VIMAGE # Kernel name
+
+################################################################################
+##################### ENABLE NON-INHERITED OPTIONS/DEVICES #####################
+################################################################################
+
+#################### Non-GENERIC options
+
+#
+# Network Virtualization for Jails
+#
+options VIMAGE # vnet paravirtualization
+
+#
+# Netgraph based bridging for vnet jails
+# NB: Not strictly necessary; will load automatically via KLD when needed
+#
+options NETGRAPH # netgraph(4) system
+options NETGRAPH_BRIDGE # ng_bridge(4)
+options NETGRAPH_EIFACE # ng_eiface(4)
+options NETGRAPH_ETHER # ng_ether(4)
+options NETGRAPH_SOCKET # ng_socket(4)
+
+#################### Non-GENERIC devices
+
+#
+# if_bridge based bridging for vnet jails
+# NB: Not strictly necessary; will load automatically via KLD when needed
+#
+device epair # epair(4)
+device if_bridge # if_bridge(4)
+
+################################################################################
+################ DISABLE UNNECESSARY INHERITED OPTIONS/DEVICES ################
+################################################################################
+
+#################### Disable select inherited options
+
+# none
+
+#################### Disable select inherited devices
+
+# none
+
+################################################################################
+# END
+################################################################################
diff --git a/share/examples/jails/jail.xxx.conf b/share/examples/jails/jail.xxx.conf
new file mode 100644
index 000000000000..8ada4aa0dd9d
--- /dev/null
+++ b/share/examples/jails/jail.xxx.conf
@@ -0,0 +1,34 @@
+
+xxx {
+ host.hostname = "xxx.yyy"; # hostname
+ path = "/vm/xxx"; # root directory
+
+ exec.clean;
+ exec.system_user = "root";
+ exec.jail_user = "root";
+
+ #
+ # NB: Below 4-lines required
+ #
+ vnet;
+ # netgraph
+ vnet.interface = "ng0_xxx"; # vnet interface(s)
+ exec.prestart += "jng bridge xxx em0"; # bridge interface(s)
+ exec.poststop += "jng shutdown xxx"; # destroy interface(s)
+ # if_bridge
+ #vnet.interface = "e0b_xxx"; # vnet interface(s)
+ #exec.prestart += "jib addm xxx em0"; # bridge interface(s)
+ #exec.poststop += "jib destroy xxx"; # destroy interface(s)
+
+ # Standard recipe
+ exec.start += "/bin/sh /etc/rc";
+ exec.stop = "/bin/sh /etc/rc.shutdown jail";
+ exec.consolelog = "/var/log/jail_xxx_console.log";
+ mount.devfs; # mount devfs
+
+ # Optional (default off)
+ #devfs_ruleset = "11"; # rule to unhide bpf for DHCP
+ #allow.mount; # mount /etc/fstab.xxx
+ #allow.set_hostname = 1; # Allow hostname to change
+ #allow.sysvipc = 1; # Allow SysV Interprocess Comm.
+}
diff --git a/share/examples/jails/jib b/share/examples/jails/jib
new file mode 100755
index 000000000000..55d908438b3e
--- /dev/null
+++ b/share/examples/jails/jib
@@ -0,0 +1,417 @@
+#!/bin/sh
+#-
+# Copyright (c) 2016 Devin Teske
+# 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.
+#
+#
+############################################################ IDENT(1)
+#
+# $Title: if_bridge(4) management script for vnet jails $
+#
+############################################################ INFORMATION
+#
+# Use this tool with jail.conf(5) (or rc.conf(5) ``legacy'' configuration) to
+# manage `vnet' interfaces for jails. Designed to automate the creation of vnet
+# interface(s) during jail `prestart' and destroy said interface(s) during jail
+# `poststop'.
+#
+# In jail.conf(5) format:
+#
+# ### BEGIN EXCERPT ###
+#
+# xxx {
+# host.hostname = "xxx.yyy";
+# path = "/vm/xxx";
+#
+# #
+# # NB: Below 2-lines required
+# # NB: The number of eNb_xxx interfaces should match the number of
+# # arguments given to `jib addm xxx' in exec.prestart value.
+# #
+# vnet;
+# vnet.interface = e0b_xxx, e1b_xxx, ...;
+#
+# exec.clean;
+# exec.system_user = "root";
+# exec.jail_user = "root";
+#
+# #
+# # NB: Below 2-lines required
+# # NB: The number of arguments after `jib addm xxx' should match
+# # the number of eNb_xxx arguments in vnet.interface value.
+# #
+# exec.prestart += "jib addm xxx em0 em1 ...";
+# exec.poststop += "jib destroy xxx";
+#
+# # Standard recipe
+# exec.start += "/bin/sh /etc/rc";
+# exec.stop = "/bin/sh /etc/rc.shutdown jail";
+# exec.consolelog = "/var/log/jail_xxx_console.log";
+# mount.devfs;
+#
+# # Optional (default off)
+# #allow.mount;
+# #allow.set_hostname = 1;
+# #allow.sysvipc = 1;
+# #devfs_ruleset = "11"; # rule to unhide bpf for DHCP
+# }
+#
+# ### END EXCERPT ###
+#
+# In rc.conf(5) ``legacy'' format (used when /etc/jail.conf does not exist):
+#
+# ### BEGIN EXCERPT ###
+#
+# jail_enable="YES"
+# jail_list="xxx"
+#
+# #
+# # Global presets for all jails
+# #
+# jail_devfs_enable="YES" # mount devfs
+#
+# #
+# # Global options (default off)
+# #
+# #jail_mount_enable="YES" # mount /etc/fstab.{name}
+# #jail_set_hostname_allow="YES" # Allow hostname to change
+# #jail_sysvipc_allow="YES" # Allow SysV Interprocess Comm.
+#
+# # xxx
+# jail_xxx_hostname="xxx.shxd.cx" # hostname
+# jail_xxx_rootdir="/vm/xxx" # root directory
+# jail_xxx_vnet_interfaces="e0b_xxx e1bxxx ..." # vnet interface(s)
+# jail_xxx_exec_prestart0="jib addm xxx em0 em1 ..." # bridge interface(s)
+# jail_xxx_exec_poststop0="jib destroy xxx" # destroy interface(s)
+# #jail_xxx_mount_enable="YES" # mount /etc/fstab.xxx
+# #jail_xxx_devfs_ruleset="11" # rule to unhide bpf for DHCP
+#
+# ### END EXCERPT ###
+#
+# Note that the legacy rc.conf(5) format is converted to
+# /var/run/jail.{name}.conf by /etc/rc.d/jail if jail.conf(5) is missing.
+#
+# ASIDE: dhclient(8) inside a vnet jail...
+#
+# To allow dhclient(8) to work inside a vnet jail, make sure the following
+# appears in /etc/devfs.rules (which should be created if it doesn't exist):
+#
+# [devfsrules_jail=11]
+# add include $devfsrules_hide_all
+# add include $devfsrules_unhide_basic
+# add include $devfsrules_unhide_login
+# add path 'bpf*' unhide
+#
+# And set ether devfs.ruleset="11" (jail.conf(5)) or
+# jail_{name}_devfs_ruleset="11" (rc.conf(5)).
+#
+# NB: While this tool can't create every type of desirable topology, it should
+# handle most setups, minus some which considered exotic or purpose-built.
+#
+############################################################ GLOBALS
+
+pgm="${0##*/}" # Program basename
+
+#
+# Global exit status
+#
+SUCCESS=0
+FAILURE=1
+
+############################################################ FUNCTIONS
+
+usage()
+{
+ local action usage descr
+ exec >&2
+ echo "Usage: $pgm action [arguments]"
+ echo "Actions:"
+ for action in \
+ addm \
+ show \
+ show1 \
+ destroy \
+ ; do
+ eval usage=\"\$jib_${action}_usage\"
+ [ "$usage" ] || continue
+ eval descr=\"\$jib_${action}_descr\"
+ printf "\t%s\n\t\t%s\n" "$usage" "$descr"
+ done
+ exit $FAILURE
+}
+
+action_usage()
+{
+ local usage descr action="$1"
+ eval usage=\"\$jib_${action}_usage\"
+ echo "Usage: $pgm $usage" >&2
+ eval descr=\"\$jib_${action}_descr\"
+ printf "\t%s\n" "$descr"
+ exit $FAILURE
+}
+
+derive_mac()
+{
+ local OPTIND=1 OPTARG __flag
+ local __mac_num= __make_pair=
+ while getopts 2n: __flag; do
+ case "$__flag" in
+ 2) __make_pair=1 ;;
+ n) __mac_num=${OPTARG%%[^0-9]*} ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ if [ ! "$__mac_num" ]; then
+ eval __mac_num=\${_${iface}_num:--1}
+ __mac_num=$(( $__mac_num + 1 ))
+ eval _${iface}_num=\$__mac_num
+ fi
+
+ local __iface="$1" __name="$2" __var_to_set="$3" __var_to_set_b="$4"
+ local __iface_devid __new_devid __num __new_devid_b
+ #
+ # Calculate MAC address derived from given iface.
+ #
+ # The formula I'm using is ``NP:SS:SS:II:II:II'' where:
+ # + N denotes 4 bits used as a counter to support branching
+ # each parent interface up to 15 times under the same jail
+ # name (see S below).
+ # + P denotes the special nibble whose value, if one of
+ # 2, 6, A, or E (but usually 2) denotes a privately
+ # administered MAC address (while remaining routable).
+ # + S denotes 16 bits, the sum(1) value of the jail name.
+ # + I denotes bits that are inherited from parent interface.
+ #
+ # The S bits are a CRC-16 checksum of NAME, allowing the jail
+ # to change link numbers in ng_bridge(4) without affecting the
+ # MAC address. Meanwhile, if...
+ # + the jail NAME changes (e.g., it was duplicated and given
+ # a new name with no other changes)
+ # + the underlying network interface changes
+ # + the jail is moved to another host
+ # the MAC address will be recalculated to a new, similarly
+ # unique value preventing conflict.
+ #
+ __iface_devid=$( ifconfig $__iface ether | awk '/ether/,$0=$2' )
+ # ??:??:??:II:II:II
+ __new_devid=${__iface_devid#??:??:??} # => :II:II:II
+ # => :SS:SS:II:II:II
+ __num=$( set -- `echo -n "$__name" | sum` && echo $1 )
+ __new_devid=$( printf :%02x:%02x \
+ $(( $__num >> 8 & 255 )) $(( $__num & 255 )) )$__new_devid
+ # => P:SS:SS:II:II:II
+ case "$__iface_devid" in
+ ?2:*) __new_devid=a$__new_devid __new_devid_b=e$__new_devid ;;
+ ?[Ee]:*) __new_devid=2$__new_devid __new_devid_b=6$__new_devid ;;
+ *) __new_devid=2$__new_devid __new_devid_b=e$__new_devid
+ esac
+ # => NP:SS:SS:II:II:II
+ __new_devid=$( printf %x $(( $__mac_num & 15 )) )$__new_devid
+ __new_devid_b=$( printf %x $(( $__mac_num & 15 )) )$__new_devid_b
+
+ #
+ # Return derivative MAC address(es)
+ #
+ if [ "$__make_pair" ]; then
+ if [ "$__var_to_set" -a "$__var_to_set_b" ]; then
+ eval $__var_to_set=\$__new_devid
+ eval $__var_to_set_b=\$__new_devid_b
+ else
+ echo $__new_devid $__new_devid_b
+ fi
+ else
+ if [ "$__var_to_set" ]; then
+ eval $__var_to_set=\$__new_devid
+ else
+ echo $__new_devid
+ fi
+ fi
+}
+
+mustberoot_to_continue()
+{
+ if [ "$( id -u )" -ne 0 ]; then
+ echo "Must run as root!" >&2
+ exit $FAILURE
+ fi
+}
+
+jib_addm_usage="addm [-b BRIDGE_NAME] NAME [!]iface0 [[!]iface1 ...]"
+jib_addm_descr="Creates e0b_NAME [e1b_NAME ...]"
+jib_addm()
+{
+ local OPTIND=1 OPTARG flag bridge=bridge
+ while getopts b: flag; do
+ case "$flag" in
+ b) bridge="${OPTARG:-bridge}" ;;
+ *) action_usage addm # NOTREACHED
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ local name="$1"
+ [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -gt 1 ] ||
+ action_usage addm # NOTREACHED
+ shift 1 # name
+
+ mustberoot_to_continue
+
+ local iface eiface_devid_a eiface_devid_b
+ local new no_derive num quad i=0
+ for iface in $*; do
+
+ no_derive=
+ case "$iface" in
+ !*) iface=${iface#!} no_derive=1 ;;
+ esac
+
+ # Make sure the interface doesn't exist already
+ if ifconfig "e${i}a_$name" > /dev/null 2>&1; then
+ i=$(( $i + 1 ))
+ continue
+ fi
+
+ # Bring the interface up
+ ifconfig $iface up || return
+
+ # Make sure the interface has been bridged
+ if ! ifconfig "$iface$bridge" > /dev/null 2>&1; then
+ new=$( ifconfig bridge create ) || return
+ ifconfig $new addm $iface || return
+ ifconfig $new name "$iface$bridge" || return
+ ifconfig "$iface$bridge" up || return
+ fi
+
+ # Create a new interface to the bridge
+ new=$( ifconfig epair create ) || return
+ ifconfig "$iface$bridge" addm $new || return
+
+ # Rename the new interface
+ ifconfig $new name "e${i}a_$name" || return
+ ifconfig ${new%a}b name "e${i}b_$name" || return
+ ifconfig "e${i}a_$name" up || return
+ ifconfig "e${i}b_$name" up || return
+
+ #
+ # Set the MAC address of the new interface using a sensible
+ # algorithm to prevent conflicts on the network.
+ #
+ eiface_devid_a= eiface_devid_b=
+ [ "$no_derive" ] || derive_mac -2 $iface "$name" \
+ eiface_devid_a eiface_devid_b
+ if [ "$eiface_devid_a" -a "$eiface_devid_b" ]; then
+ ifconfig "e${i}a_$name" ether $eiface_devid_a
+ ifconfig "e${i}b_$name" ether $eiface_devid_b
+ fi > /dev/null 2>&1
+
+ i=$(( $i + 1 ))
+ done # for iface
+}
+
+jib_show_usage="show"
+jib_show_descr="List possible NAME values for \`show NAME'"
+jib_show1_usage="show NAME"
+jib_show1_descr="Lists e0b_NAME [e1b_NAME ...]"
+jib_show2_usage="show [NAME]"
+jib_show()
+{
+ local OPTIND=1 OPTARG flag
+ while getopts "" flag; do
+ case "$flag" in
+ *) action_usage show2 # NOTREACHED
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+ if [ $# -eq 0 ]; then
+ ifconfig | awk '
+ /^[^:[:space:]]+:/ {
+ iface = $1
+ sub(/:.*/, "", iface)
+ next
+ }
+ $1 == "groups:" {
+ for (n = split($0, group); n > 1; n--) {
+ if (group[n] != "bridge") continue
+ print iface
+ next
+ }
+ }' |
+ xargs -rn1 ifconfig |
+ awk '$1 == "member:" &&
+ sub(/^e[[:digit:]]+a_/, "", $2), $0 = $2' |
+ sort -u
+ return
+ fi
+ ifconfig | awk -v name="$1" '
+ match($0, /^e[[:digit:]]+a_/) && sub(/:.*/, "") &&
+ substr($1, RSTART + RLENGTH) == name
+ ' | sort
+}
+
+jib_destroy_usage="destroy NAME"
+jib_destroy_descr="Destroy e0b_NAME [e1b_NAME ...]"
+jib_destroy()
+{
+ local OPTIND=1 OPTARG flag
+ while getopts "" flag; do
+ case "$flag" in
+ *) action_usage destroy # NOTREACHED
+ esac
+ done
+ shift $(( $OPTIND -1 ))
+ local name="$1"
+ [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] ||
+ action_usage destroy # NOTREACHED
+ mustberoot_to_continue
+ jib_show "$name" | xargs -rn1 -I eiface ifconfig eiface destroy
+}
+
+############################################################ MAIN
+
+#
+# Command-line arguments
+#
+action="$1"
+[ "$action" ] || usage # NOTREACHED
+
+#
+# Validate action argument
+#
+if [ "$BASH_VERSION" ]; then
+ type="$( type -t "jib_$action" )" || usage # NOTREACHED
+else
+ type="$( type "jib_$action" 2> /dev/null )" || usage # NOTREACHED
+fi
+case "$type" in
+*function)
+ shift 1 # action
+ eval "jib_$action" \"\$@\"
+ ;;
+*) usage # NOTREACHED
+esac
+
+################################################################################
+# END
+################################################################################
diff --git a/share/examples/jails/jng b/share/examples/jails/jng
new file mode 100755
index 000000000000..610b08f96840
--- /dev/null
+++ b/share/examples/jails/jng
@@ -0,0 +1,508 @@
+#!/bin/sh
+#-
+# Copyright (c) 2016 Devin Teske
+# 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.
+#
+#
+############################################################ IDENT(1)
+#
+# $Title: netgraph(4) management script for vnet jails $
+#
+############################################################ INFORMATION
+#
+# Use this tool with jail.conf(5) (or rc.conf(5) ``legacy'' configuration) to
+# manage `vnet' interfaces for jails. Designed to automate the creation of vnet
+# interface(s) during jail `prestart' and destroy said interface(s) during jail
+# `poststop'.
+#
+# In jail.conf(5) format:
+#
+# ### BEGIN EXCERPT ###
+#
+# xxx {
+# host.hostname = "xxx.yyy";
+# path = "/vm/xxx";
+#
+# #
+# # NB: Below 2-lines required
+# # NB: The number of ngN_xxx interfaces should match the number of
+# # arguments given to `jng bridge xxx' in exec.prestart value.
+# #
+# vnet;
+# vnet.interface = ng0_xxx, ng1_xxx, ...;
+#
+# exec.clean;
+# exec.system_user = "root";
+# exec.jail_user = "root";
+#
+# #
+# # NB: Below 2-lines required
+# # NB: The number of arguments after `jng bridge xxx' should match
+# # the number of ngN_xxx arguments in vnet.interface value.
+# #
+# exec.prestart += "jng bridge xxx em0 em1 ...";
+# exec.poststop += "jng shutdown xxx";
+#
+# # Standard recipe
+# exec.start += "/bin/sh /etc/rc";
+# exec.stop = "/bin/sh /etc/rc.shutdown jail";
+# exec.consolelog = "/var/log/jail_xxx_console.log";
+# mount.devfs;
+#
+# # Optional (default off)
+# #allow.mount;
+# #allow.set_hostname = 1;
+# #allow.sysvipc = 1;
+# #devfs_ruleset = "11"; # rule to unhide bpf for DHCP
+# }
+#
+# ### END EXCERPT ###
+#
+# In rc.conf(5) ``legacy'' format (used when /etc/jail.conf does not exist):
+#
+# ### BEGIN EXCERPT ###
+#
+# jail_enable="YES"
+# jail_list="xxx"
+#
+# #
+# # Global presets for all jails
+# #
+# jail_devfs_enable="YES" # mount devfs
+#
+# #
+# # Global options (default off)
+# #
+# #jail_mount_enable="YES" # mount /etc/fstab.{name}
+# #jail_set_hostname_allow="YES" # Allow hostname to change
+# #jail_sysvipc_allow="YES" # Allow SysV Interprocess Comm.
+#
+# # xxx
+# jail_xxx_hostname="xxx.shxd.cx" # hostname
+# jail_xxx_rootdir="/vm/xxx" # root directory
+# jail_xxx_vnet_interfaces="ng0_xxx ng1xxx ..." # vnet interface(s)
+# jail_xxx_exec_prestart0="jng bridge xxx em0 em1 ..." # bridge interface(s)
+# jail_xxx_exec_poststop0="jng shutdown xxx" # destroy interface(s)
+# #jail_xxx_mount_enable="YES" # mount /etc/fstab.xxx
+# #jail_xxx_devfs_ruleset="11" # rule to unhide bpf for DHCP
+#
+# ### END EXCERPT ###
+#
+# Note that the legacy rc.conf(5) format is converted to
+# /var/run/jail.{name}.conf by /etc/rc.d/jail if jail.conf(5) is missing.
+#
+# ASIDE: dhclient(8) inside a vnet jail...
+#
+# To allow dhclient(8) to work inside a vnet jail, make sure the following
+# appears in /etc/devfs.rules (which should be created if it doesn't exist):
+#
+# [devfsrules_jail=11]
+# add include $devfsrules_hide_all
+# add include $devfsrules_unhide_basic
+# add include $devfsrules_unhide_login
+# add path 'bpf*' unhide
+#
+# And set ether devfs.ruleset="11" (jail.conf(5)) or
+# jail_{name}_devfs_ruleset="11" (rc.conf(5)).
+#
+# NB: While this tool can't create every type of desirable topology, it should
+# handle most setups, minus some which considered exotic or purpose-built.
+#
+############################################################ GLOBALS
+
+pgm="${0##*/}" # Program basename
+
+#
+# Global exit status
+#
+SUCCESS=0
+FAILURE=1
+
+############################################################ FUNCTIONS
+
+usage()
+{
+ local action usage descr
+ exec >&2
+ echo "Usage: $pgm action [arguments]"
+ echo "Actions:"
+ for action in \
+ bridge \
+ graph \
+ show \
+ show1 \
+ shutdown \
+ stats \
+ ; do
+ eval usage=\"\$jng_${action}_usage\"
+ [ "$usage" ] || continue
+ eval descr=\"\$jng_${action}_descr\"
+ printf "\t%s\n\t\t%s\n" "$usage" "$descr"
+ done
+ exit $FAILURE
+}
+
+action_usage()
+{
+ local usage descr action="$1"
+ eval usage=\"\$jng_${action}_usage\"
+ echo "Usage: $pgm $usage" >&2
+ eval descr=\"\$jng_${action}_descr\"
+ printf "\t%s\n" "$descr"
+ exit $FAILURE
+}
+
+derive_mac()
+{
+ local OPTIND=1 OPTARG __flag
+ local __mac_num= __make_pair=
+ while getopts 2n: __flag; do
+ case "$__flag" in
+ 2) __make_pair=1 ;;
+ n) __mac_num=${OPTARG%%[^0-9]*} ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ if [ ! "$__mac_num" ]; then
+ eval __mac_num=\${_${iface}_num:--1}
+ __mac_num=$(( $__mac_num + 1 ))
+ eval _${iface}_num=\$__mac_num
+ fi
+
+ local __iface="$1" __name="$2" __var_to_set="$3" __var_to_set_b="$4"
+ local __iface_devid __new_devid __num __new_devid_b
+ #
+ # Calculate MAC address derived from given iface.
+ #
+ # The formula I'm using is ``NP:SS:SS:II:II:II'' where:
+ # + N denotes 4 bits used as a counter to support branching
+ # each parent interface up to 15 times under the same jail
+ # name (see S below).
+ # + P denotes the special nibble whose value, if one of
+ # 2, 6, A, or E (but usually 2) denotes a privately
+ # administered MAC address (while remaining routable).
+ # + S denotes 16 bits, the sum(1) value of the jail name.
+ # + I denotes bits that are inherited from parent interface.
+ #
+ # The S bits are a CRC-16 checksum of NAME, allowing the jail
+ # to change link numbers in ng_bridge(4) without affecting the
+ # MAC address. Meanwhile, if...
+ # + the jail NAME changes (e.g., it was duplicated and given
+ # a new name with no other changes)
+ # + the underlying network interface changes
+ # + the jail is moved to another host
+ # the MAC address will be recalculated to a new, similarly
+ # unique value preventing conflict.
+ #
+ __iface_devid=$( ifconfig $__iface ether | awk '/ether/,$0=$2' )
+ # ??:??:??:II:II:II
+ __new_devid=${__iface_devid#??:??:??} # => :II:II:II
+ # => :SS:SS:II:II:II
+ __num=$( set -- `echo -n "$__name" | sum` && echo $1 )
+ __new_devid=$( printf :%02x:%02x \
+ $(( $__num >> 8 & 255 )) $(( $__num & 255 )) )$__new_devid
+ # => P:SS:SS:II:II:II
+ case "$__iface_devid" in
+ ?2:*) __new_devid=a$__new_devid __new_devid_b=e$__new_devid ;;
+ ?[Ee]:*) __new_devid=2$__new_devid __new_devid_b=6$__new_devid ;;
+ *) __new_devid=2$__new_devid __new_devid_b=e$__new_devid
+ esac
+ # => NP:SS:SS:II:II:II
+ __new_devid=$( printf %x $(( $__mac_num & 15 )) )$__new_devid
+ __new_devid_b=$( printf %x $(( $__mac_num & 15 )) )$__new_devid_b
+
+ #
+ # Return derivative MAC address(es)
+ #
+ if [ "$__make_pair" ]; then
+ if [ "$__var_to_set" -a "$__var_to_set_b" ]; then
+ eval $__var_to_set=\$__new_devid
+ eval $__var_to_set_b=\$__new_devid_b
+ else
+ echo $__new_devid $__new_devid_b
+ fi
+ else
+ if [ "$__var_to_set" ]; then
+ eval $__var_to_set=\$__new_devid
+ else
+ echo $__new_devid
+ fi
+ fi
+}
+
+mustberoot_to_continue()
+{
+ if [ "$( id -u )" -ne 0 ]; then
+ echo "Must run as root!" >&2
+ exit $FAILURE
+ fi
+}
+
+jng_bridge_usage="bridge [-b BRIDGE_NAME] NAME [!|=]iface0 [[!|=]iface1 ...]"
+jng_bridge_descr="Create ng0_NAME [ng1_NAME ...]"
+jng_bridge()
+{
+ local OPTIND=1 OPTARG flag bridge=bridge
+ while getopts b: flag; do
+ case "$flag" in
+ b) bridge="$OPTARG"
+ [ "$bridge" ] || action_usage bridge ;; # NOTREACHED
+ *) action_usage bridge # NOTREACHED
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ local name="$1"
+ [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -gt 1 ] ||
+ action_usage bridge # NOTREACHED
+ shift 1 # name
+
+ mustberoot_to_continue
+
+ local iface parent eiface eiface_devid
+ local new clone_mac no_derive num quad i=0
+ for iface in $*; do
+
+ clone_mac=
+ no_derive=
+ case "$iface" in
+ =*) iface=${iface#=} clone_mac=1 ;;
+ !*) iface=${iface#!} no_derive=1 ;;
+ esac
+
+ # Make sure the interface doesn't exist already
+ eiface=ng${i}_$name
+ if ngctl msg "$eiface:" getifname > /dev/null 2>&1; then
+ i=$(( $i + 1 ))
+ continue
+ fi
+
+ # Bring the interface up
+ ifconfig $iface up || return
+
+ # Set promiscuous mode and don't overwrite src addr
+ ngctl msg $iface: setpromisc 1 || return
+ ngctl msg $iface: setautosrc 0 || return
+
+ # Make sure the interface has been bridged
+ if ! ngctl info ${iface}bridge: > /dev/null 2>&1; then
+ ngctl mkpeer $iface: bridge lower link0 || return
+ ngctl connect $iface: $iface:lower upper link1 ||
+ return
+ ngctl name $iface:lower ${iface}bridge || return
+ fi
+
+ # Optionally create a secondary bridge
+ if [ "$bridge" != "bridge" ] &&
+ ! ngctl info "$iface$bridge:" > /dev/null 2>&1
+ then
+ num=2
+ while ngctl msg ${iface}bridge: getstats $num \
+ > /dev/null 2>&1
+ do
+ num=$(( $num + 1 ))
+ done
+ ngctl mkpeer $iface:lower bridge link$num link1 ||
+ return
+ ngctl name ${iface}bridge:link$num "$iface$bridge" ||
+ return
+ fi
+
+ # Create a new interface to the bridge
+ num=2
+ while ngctl msg "$iface$bridge:" getstats $num > /dev/null 2>&1
+ do
+ num=$(( $num + 1 ))
+ done
+ ngctl mkpeer "$iface$bridge:" eiface link$num ether || return
+
+ # Rename the new interface
+ while [ ${#eiface} -gt 15 ]; do # OS limitation
+ eiface=${eiface%?}
+ done
+ new=$( set -- `ngctl show -n "$iface$bridge:link$num"` &&
+ echo $2 ) || return
+ ngctl name "$iface$bridge:link$num" $eiface || return
+ ifconfig $new name $eiface || return
+ ifconfig $eiface up || return
+
+ #
+ # Set the MAC address of the new interface using a sensible
+ # algorithm to prevent conflicts on the network.
+ #
+ eiface_devid=
+ if [ "$clone_mac" ]; then
+ eiface_devid=$( ifconfig $iface ether |
+ awk '/ether/,$0=$2' )
+ elif [ ! "$no_derive" ]; then
+ derive_mac $iface "$name" eiface_devid
+ fi
+ [ "$eiface_devid" ] &&
+ ifconfig $eiface ether $eiface_devid > /dev/null 2>&1
+
+ i=$(( $i + 1 ))
+ done # for iface
+}
+
+jng_graph_usage="graph [-f] [-T type] [-o output]"
+jng_graph_descr="Generate network graph (default output is \`jng.svg')"
+jng_graph()
+{
+ local OPTIND=1 OPTARG flag
+ local output=jng.svg output_type= force=
+ while getopts fo:T: flag; do
+ case "$flag" in
+ f) force=1 ;;
+ o) output="$OPTARG" ;;
+ T) output_type="$OPTARG" ;;
+ *) action_usage graph # NOTREACHED
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+ [ $# -eq 0 -a "$output" ] || action_usage graph # NOTREACHED
+ mustberoot_to_continue
+ if [ -e "$output" -a ! "$force" ]; then
+ echo "$output: Already exists (use \`-f' to overwrite)" >&2
+ return $FAILURE
+ fi
+ if [ ! "$output_type" ]; then
+ local valid suffix
+ valid=$( dot -Txxx 2>&1 )
+ for suffix in ${valid##*:}; do
+ [ "$output" != "${output%.$suffix}" ] || continue
+ output_type=$suffix
+ break
+ done
+ fi
+ ngctl dot | dot ${output_type:+-T "$output_type"} -o "$output"
+}
+
+jng_show_usage="show"
+jng_show_descr="List possible NAME values for \`show NAME'"
+jng_show1_usage="show NAME"
+jng_show1_descr="Lists ng0_NAME [ng1_NAME ...]"
+jng_show2_usage="show [NAME]"
+jng_show()
+{
+ local OPTIND=1 OPTARG flag
+ while getopts "" flag; do
+ case "$flag" in
+ *) action_usage show2 # NOTREACHED
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+ mustberoot_to_continue
+ if [ $# -eq 0 ]; then
+ ngctl ls | awk '$4=="bridge",$0=$2' |
+ xargs -rn1 -Ibridge ngctl show bridge: |
+ awk 'sub(/^ng[[:digit:]]+_/, "", $2), $0 = $2' |
+ sort -u
+ return
+ fi
+ ngctl ls | awk -v name="$1" '
+ match($2, /^ng[[:digit:]]+_/) &&
+ substr($2, RSTART + RLENGTH) == name &&
+ $4 == "eiface", $0 = $2
+ ' | sort
+}
+
+jng_shutdown_usage="shutdown NAME"
+jng_shutdown_descr="Shutdown ng0_NAME [ng1_NAME ...]"
+jng_shutdown()
+{
+ local OPTIND=1 OPTARG flag
+ while getopts "" flag; do
+ case "$flag" in
+ *) action_usage shutdown # NOTREACHED
+ esac
+ done
+ shift $(( $OPTIND -1 ))
+ local name="$1"
+ [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] ||
+ action_usage shutdown # NOTREACHED
+ mustberoot_to_continue
+ jng_show "$name" | xargs -rn1 -I eiface ngctl shutdown eiface:
+}
+
+jng_stats_usage="stats NAME"
+jng_stats_descr="Show ng_bridge link statistics for NAME interfaces"
+jng_stats()
+{
+ local OPTIND=1 OPTARG flag
+ while getopts "" flag; do
+ case "$flag" in
+ *) action_usage stats # NOTREACHED
+ esac
+ done
+ shift $(( $OPTIND -1 ))
+ local name="$1"
+ [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] ||
+ action_usage stats # NOTREACHED
+ mustberoot_to_continue
+ for eiface in $( jng_show "$name" ); do
+ echo "$eiface:"
+ ngctl show $eiface: | awk '
+ $3 == "bridge" && $5 ~ /^link/ {
+ bridge = $2
+ link = substr($5, 5)
+ system(sprintf("ngctl msg %s: getstats %u",
+ bridge, link))
+ }' | fmt 2 | awk '
+ /=/ && fl = index($0, "=") {
+ printf "%20s = %s\n",
+ substr($0, 0, fl-1),
+ substr($0, 0, fl+1)
+ }
+ ' # END-QUOTE
+ done
+}
+
+############################################################ MAIN
+
+#
+# Command-line arguments
+#
+action="$1"
+[ "$action" ] || usage # NOTREACHED
+
+#
+# Validate action argument
+#
+if [ "$BASH_VERSION" ]; then
+ type="$( type -t "jng_$action" )" || usage # NOTREACHED
+else
+ type="$( type "jng_$action" 2> /dev/null )" || usage # NOTREACHED
+fi
+case "$type" in
+*function)
+ shift 1 # action
+ eval "jng_$action" \"\$@\"
+ ;;
+*) usage # NOTREACHED
+esac
+
+################################################################################
+# END
+################################################################################
diff --git a/share/examples/jails/rc.conf.jails b/share/examples/jails/rc.conf.jails
new file mode 100644
index 000000000000..b1e0d6187b4e
--- /dev/null
+++ b/share/examples/jails/rc.conf.jails
@@ -0,0 +1,75 @@
+
+###############################################################################
+############################# JAIL CONFIGURATIONS #############################
+###############################################################################
+
+jail_enable="YES"
+jail_list="XXX"
+
+#
+# Global presets for all jails
+#
+jail_devfs_enable="YES" # mount devfs
+# Optional (default off)
+#jail_sysvipc_allow="YES" # Allow SysV Interprocess Comm.
+#jail_set_hostname_allow="YES" # Allow hostname to change
+
+#
+# To allow dhclient(8) to work inside a jail, make sure the following appears
+# in /etc/devfs.rules (which should be created if it doesn't exist):
+#
+# [devfsrules_jail=11]
+# add include $devfsrules_hide_all
+# add include $devfsrules_unhide_basic
+# add include $devfsrules_unhide_login
+# add path 'bpf*' unhide
+#
+
+############################################################ JAILS
+
+# NETGRAPH TEMPLATE (copy/pate; then replace {name} with short name for jail)
+#
+# {name}
+#
+#jail_{name}_hostname="{name}.shxd.cx" # hostname
+#jail_{name}_rootdir="/vm/{name}" # root directory
+#jail_{name}_vnet_interfaces="ng0_{name}" # vnet interface(s)
+#jail_{name}_exec_prestart0="jng bridge {name} em0" # bridge interface(s)
+#jail_{name}_exec_poststop0="jng shutdown {name}" # destroy interface(s)
+# Optional (default off)
+#jail_{name}_devfs_ruleset="11" # rule to unhide bpf for DHCP
+#jail_{name}_mount_enable="YES" # mount /etc/fstab.{name}
+
+# IF_BRIDGE TEMPLATE (copy/pate; then replace {name} with short name for jail)
+#
+# {name}
+#
+#jail_{name}_hostname="{name}.shxd.cx" # hostname
+#jail_{name}_rootdir="/vm/{name}" # root directory
+#jail_{name}_vnet_interfaces="e0b_{name}" # vnet interface(s)
+#jail_{name}_exec_prestart0="jib addm {name} em0" # bridge interface(s)
+#jail_{name}_exec_poststop0="jib destroy {name}" # destroy interface(s)
+# Optional (default off)
+#jail_{name}_devfs_ruleset="11" # rule to unhide bpf for DHCP
+#jail_{name}_mount_enable="YES" # mount /etc/fstab.{name}
+
+#
+# XXX
+#
+jail_XXX_hostname="XXX.YYY" # hostname
+jail_XXX_rootdir="/vm/XXX" # root directory
+# netgraph
+jail_XXX_vnet_interface="ng0_XXX" # vnet interface(s)
+jail_XXX_exec_prestart0="jng bridge XXX em0" # bridge interface(s)
+jail_XXX_exec_poststop0="jng shutdown XXX" # destroy interface(s)
+# if_bridge
+#jail_XXX_vnet_interface="e0b_XXX" # vnet interface(s)
+#jail_XXX_exec_prestart0="jib addm XXX em0" # bridge interface(s)
+#jail_XXX_exec_poststop0="jib destroy XXX" # destroy interface(s)
+# Optional (default off)
+#jail_XXX_devfs_ruleset="11" # rule to unhide bpf for DHCP
+#jail_XXX_mount_enable="YES" # mount /etc/fstab.XXX
+
+################################################################################
+# END
+################################################################################
diff --git a/share/examples/jails/rcjail.xxx.conf b/share/examples/jails/rcjail.xxx.conf
new file mode 100644
index 000000000000..8757219a97f3
--- /dev/null
+++ b/share/examples/jails/rcjail.xxx.conf
@@ -0,0 +1,24 @@
+
+jail_XXX_hostname="XXX.YYY" # hostname
+jail_XXX_rootdir="/vm/XXX" # root directory
+
+#
+# NB: Below 3 lines required
+#
+# netgraph
+jail_XXX_vnet_interface="ng0_XXX" # vnet interface(s)
+jail_XXX_exec_prestart0="jng bridge XXX em0" # bridge interface(s)
+jail_XXX_exec_poststop0="jng shutdown XXX" # destroy interface(s)
+# if_bridge
+#jail_XXX_vnet_interface="e0b_XXX" # vnet interface(s)
+#jail_XXX_exec_prestart0="jib addm XXX em0" # bridge interface(s)
+#jail_XXX_exec_poststop0="jib destroy XXX" # destroy interface(s)
+
+# Standard recipe
+jail_XXX_devfs_enable="YES" # mount devfs
+
+# Optional (default off)
+#jail_XXX_devfs_ruleset="11" # rule to unhide bpf for DHCP
+#jail_XXX_mount_enable="YES" # mount /etc/fstab.XXX
+#jail_XXX_set_hostname_allow="YES" # Allow hostname to change
+#jail_XXX_sysvipc_allow="YES" # Allow SysV Interprocess Comm.
diff --git a/share/examples/kld/Makefile b/share/examples/kld/Makefile
new file mode 100644
index 000000000000..3116f547e057
--- /dev/null
+++ b/share/examples/kld/Makefile
@@ -0,0 +1,73 @@
+# 08 Nov 1998
+#
+# Makefile for sample programs for kld modules package
+#
+# 08 Nov 1998 Rajesh Vaidheeswarran - adapted from lkm Makefile
+#
+# Copyright (c) 1998 Rajesh Vaidheeswarran
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Rajesh Vaidheeswarran.
+# 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``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 RAJESH VAIDHEESWARRAN BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# Copyright (c) 1993 Terrence R. Lambert.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Terrence R. Lambert.
+# 4. The name Terrence R. Lambert may not be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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.
+#
+#
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld
+SUBDIR= cdev dyn_sysctl firmware khelp random_adaptor syscall
+
+.include <bsd.subdir.mk>
diff --git a/share/examples/kld/cdev/Makefile b/share/examples/kld/cdev/Makefile
new file mode 100644
index 000000000000..706cb2dcbae9
--- /dev/null
+++ b/share/examples/kld/cdev/Makefile
@@ -0,0 +1,8 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/cdev
+SUBDIR= module test
+
+load unload: _SUBDIR
+
+.include <bsd.subdir.mk>
diff --git a/share/examples/kld/cdev/README b/share/examples/kld/cdev/README
new file mode 100644
index 000000000000..617a3460f86d
--- /dev/null
+++ b/share/examples/kld/cdev/README
@@ -0,0 +1,130 @@
+# Copyright (c) 1998 Rajesh Vaidheeswarran
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Rajesh Vaidheeswarran
+# 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``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 RAJESH VAIDHEESWARRAN BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# Copyright (c) 1993 Terrence R. Lambert.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Terrence R. Lambert.
+# 4. The name Terrence R. Lambert may not be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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.
+#
+#
+
+1.0 Overview
+
+ This is the README file for the sample kld module
+ that mimics a character device driver.
+
+ A kld module may be used to load any data or
+ program into the kernel that can be made available by
+ modifying a table, pointer, or other kernel data to inform
+ the kernel that the module should be used instead of the
+ previous code/data path.
+
+ Generally, it is assumed that a loadable module is one of
+ a set of similar modules (such as a file system or console
+ terminal emulation), and that the reference is through a
+ table (such as vfssw[]), and that a "special" value is
+ assigned to the slots which are allowed to be replaced.
+ This is not enforced, so you may use the kld module
+ any way you see fit.
+
+ As with the loadable system calls, it may be desirable to
+ allow the module loader to replace an *existing* entry to
+ try out changes to kernel code without rebuilding and
+ booting from the new kernel.
+
+ The idea behind this example is to show some interaction
+ with the device driver. Therefore the flow of the code that
+ this driver is aimed at is as follows:
+
+ open(2) -> ioctl(2) -> write(2) -> read(2) -> close(2).
+
+ We will first open the device in the /dev/ directory; then
+ we will send an ioctl message to it using ioctl(2) call;
+ then write a small string via the write(2) call. This string
+ we write to the device will be stored in a static buffer,
+ and later will be accessible via the read(2) call. Finally,
+ we will close(2) our open()'d device so that we may no
+ longer make read or write calls on it.
+
+2.0 Directions
+
+ To test the module, do the following:
+
+ cd module
+ make load
+
+ A load message (the copyright) will be printed on the console.
+
+ cd ../test
+ make load
+
+ The system call prints a message on the console when called.
+ This message will be printed when running "make load" in
+ the "test" subdirectory.
+
+
+3.0 Recovering resources
+
+ The module consumes memory when loaded; it can be freed up by
+ unloading it. To unload it, type the following from the directory
+ this file is in:
+
+ cd module
+ make unload
+
+ The miscellaneous module will be unloaded by name.
+
+
+4.0 END OF DOCUMENT
diff --git a/share/examples/kld/cdev/module/Makefile b/share/examples/kld/cdev/module/Makefile
new file mode 100644
index 000000000000..7db8ca7442c6
--- /dev/null
+++ b/share/examples/kld/cdev/module/Makefile
@@ -0,0 +1,8 @@
+# Makefile for kld char device driver.
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/${KMOD}/module
+KMOD= cdev
+SRCS= cdev.c cdevmod.c
+
+.include <bsd.kmod.mk>
diff --git a/share/examples/kld/cdev/module/cdev.c b/share/examples/kld/cdev/module/cdev.c
new file mode 100644
index 000000000000..9d10e8d03f98
--- /dev/null
+++ b/share/examples/kld/cdev/module/cdev.c
@@ -0,0 +1,182 @@
+/* 08 Nov 1998*/
+/*-
+ * cdev.c
+ *
+ * 08 Nov 1998 Rajesh Vaidheeswarran
+ *
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1998 Rajesh Vaidheeswarran
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Rajesh Vaidheeswarran.
+ * 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``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 RAJESH VAIDHEESWARRAN BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Copyright (c) 1993 Terrence R. Lambert.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Terrence R. Lambert.
+ * 4. The name Terrence R. Lambert may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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/param.h>
+#include <sys/uio.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/ioccom.h>
+#include <sys/conf.h>
+
+#include "cdev.h"
+
+/*
+ * This is the actual code for the system call... it can't be static because
+ * it is exported to another part of the module... the only place it needs
+ * to be referenced is the sysent we are interested in.
+ *
+ * To write your own system call using this as a template, you could strip
+ * out this code and use the rest as a prototype module, changing only the
+ * function names and the number of arguments to the call in the module
+ * specific "sysent".
+ *
+ * You would have to use the "-R" option of "ld" to ensure a linkable file
+ * if you were to do this, since you would need to combine multiple ".o"
+ * files into a single ".o" file for use by "modload".
+ */
+
+#define CDEV_IOCTL1 _IOR('C', 1, u_int)
+
+/* Stores string recv'd by _write() */
+static char buf[512+1];
+static size_t len;
+
+int
+mydev_open(struct cdev *dev, int flag, int otyp, struct thread *td)
+{
+ struct proc *procp = td->td_proc;
+
+ printf("mydev_open: dev_t=%lu, flag=%x, otyp=%x, procp=%p\n",
+ dev2udev(dev), flag, otyp, procp);
+ memset(&buf, '\0', 513);
+ len = 0;
+ return (0);
+}
+
+int
+mydev_close(struct cdev *dev, int flag, int otyp, struct thread *td)
+{
+ struct proc *procp = td->td_proc;
+
+ printf("mydev_close: dev_t=%lu, flag=%x, otyp=%x, procp=%p\n",
+ dev2udev(dev), flag, otyp, procp);
+ return (0);
+}
+
+int
+mydev_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode,
+ struct thread *td)
+{
+ int error = 0;
+ struct proc *procp = td->td_proc;
+
+ printf("mydev_ioctl: dev_t=%lu, cmd=%lx, arg=%p, mode=%x procp=%p\n",
+ dev2udev(dev), cmd, arg, mode, procp);
+
+ switch(cmd) {
+ case CDEV_IOCTL1:
+ printf("you called mydev_ioctl CDEV_IOCTL1\n");
+ break;
+ default:
+ printf("No such ioctl for me!\n");
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+/*
+ * mydev_write takes in a character string and saves it
+ * to buf for later accessing.
+ */
+int
+mydev_write(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ int err = 0;
+
+ printf("mydev_write: dev_t=%lu, uio=%p, ioflag=%d\n",
+ dev2udev(dev), uio, ioflag);
+
+ err = copyinstr(uio->uio_iov->iov_base, &buf, 512, &len);
+ if (err != 0) {
+ printf("Write to \"cdev\" failed.\n");
+ }
+ return(err);
+}
+
+/*
+ * The mydev_read function just takes the buf that was saved
+ * via mydev_write() and returns it to userland for
+ * accessing.
+ */
+int
+mydev_read(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ int err = 0;
+
+ printf("mydev_read: dev_t=%lu, uio=%p, ioflag=%d\n",
+ dev2udev(dev), uio, ioflag);
+
+ if (len <= 0) {
+ err = -1;
+ } else { /* copy buf to userland */
+ copystr(&buf, uio->uio_iov->iov_base, 513, &len);
+ }
+ return(err);
+}
diff --git a/share/examples/kld/cdev/module/cdev.h b/share/examples/kld/cdev/module/cdev.h
new file mode 100644
index 000000000000..0ce0dd14d359
--- /dev/null
+++ b/share/examples/kld/cdev/module/cdev.h
@@ -0,0 +1,81 @@
+/* 08 Nov 1998*/
+/*-
+ * cdev.h - header for sample kld module implementing a character device
+ * driver.
+ *
+ * 08 Nov 1998 Rajesh Vaidheeswarran
+ *
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1998 Rajesh Vaidheeswarran
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Rajesh Vaidheeswarran.
+ * 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``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 RAJESH VAIDHEESWARRAN BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Copyright (c) 1993 Terrence R. Lambert.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Terrence R. Lambert.
+ * 4. The name Terrence R. Lambert may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef __CDEV_H_
+#define __CDEV_H_
+
+d_open_t mydev_open;
+d_close_t mydev_close;
+d_ioctl_t mydev_ioctl;
+d_read_t mydev_read;
+d_write_t mydev_write;
+
+#endif
diff --git a/share/examples/kld/cdev/module/cdevmod.c b/share/examples/kld/cdev/module/cdevmod.c
new file mode 100644
index 000000000000..1df008ac017b
--- /dev/null
+++ b/share/examples/kld/cdev/module/cdevmod.c
@@ -0,0 +1,146 @@
+/* 08 Nov 1998*/
+/*-
+ * cdevmod.c - a sample kld module implementing a character device driver.
+ *
+ * 08 Nov 1998 Rajesh Vaidheeswarran
+ *
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1998 Rajesh Vaidheeswarran
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Rajesh Vaidheeswarran.
+ * 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``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 RAJESH VAIDHEESWARRAN BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Copyright (c) 1993 Terrence R. Lambert.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Terrence R. Lambert.
+ * 4. The name Terrence R. Lambert may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+
+#include "cdev.h"
+
+static struct cdevsw my_devsw = {
+ /* version */ .d_version = D_VERSION,
+ /* open */ .d_open = mydev_open,
+ /* close */ .d_close = mydev_close,
+ /* read */ .d_read = mydev_read,
+ /* write */ .d_write = mydev_write,
+ /* ioctl */ .d_ioctl = mydev_ioctl,
+ /* name */ .d_name = "cdev"
+};
+
+/*
+ * Used as the variable that is the reference to our device
+ * in devfs... we must keep this variable sane until we
+ * call kldunload.
+ */
+static struct cdev *sdev;
+
+/*
+ * This function is called each time the module is loaded or unloaded.
+ * Since we are a miscellaneous module, we have to provide whatever
+ * code is necessary to patch ourselves into the area we are being
+ * loaded to change.
+ *
+ * The stat information is basically common to all modules, so there
+ * is no real issue involved with stat; we will leave it lkm_nullcmd(),
+ * since we don't have to do anything about it.
+ */
+
+static int
+cdev_load(module_t mod, int cmd, void *arg)
+{
+ int err = 0;
+ struct make_dev_args mda;
+
+ switch (cmd) {
+ case MOD_LOAD:
+
+ /* Do any initialization that you should do with the kernel */
+
+ /* if we make it to here, print copyright on console*/
+ printf("\nSample Loaded kld character device driver\n");
+ printf("Copyright (c) 1998\n");
+ printf("Rajesh Vaidheeswarran\n");
+ printf("All rights reserved\n");
+
+ make_dev_args_init(&mda);
+ mda.mda_devsw = &my_devsw;
+ mda.mda_uid = UID_ROOT;
+ mda.mda_gid = GID_WHEEL;
+ mda.mda_mode = 0600;
+ err = make_dev_s(&mda, &sdev, "cdev");
+ break;
+
+ case MOD_UNLOAD:
+ printf("Unloaded kld character device driver\n");
+ destroy_dev(sdev);
+ break; /* Success*/
+
+ default: /* we only understand load/unload*/
+ err = EOPNOTSUPP;
+ break;
+ }
+
+ return(err);
+}
+
+/* Now declare the module to the system */
+
+DEV_MODULE(cdev, cdev_load, NULL);
diff --git a/share/examples/kld/cdev/test/Makefile b/share/examples/kld/cdev/test/Makefile
new file mode 100644
index 000000000000..3ac6e07d339f
--- /dev/null
+++ b/share/examples/kld/cdev/test/Makefile
@@ -0,0 +1,96 @@
+# 05 Jun 93
+#
+# Makefile for testmisc
+#
+# 05 Jun 93 Rajesh Vaidheeswarran Original
+#
+# Copyright (c) 1993 Rajesh Vaidheeswarran.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Rajesh Vaidheeswarran.
+# 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``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 RAJESH VAIDHEESWARRAN BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# Copyright (c) 1993 Terrence R. Lambert.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Terrence R. Lambert.
+# 4. The name Terrence R. Lambert may not be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+#
+# THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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.
+#
+#
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/cdev/test
+PROG= testcdev
+MAN=
+WARNS?= 5
+
+MODSTAT= /sbin/kldstat
+
+load:
+ @echo "This test program will call the sample kld character device ";
+ @echo "driver."
+ @echo
+ @echo "The sample driver will display a message on the"
+ @echo "system console each time an ioctl is sent to it."
+ @echo
+ @echo
+ @echo
+ @./testcdev
+
+unload:
+ @echo "This test program will cause an error if the driver"
+ @echo "has been successfully unloaded by building 'unload' in"
+ @echo "the 'module' subdirectory."
+ @echo
+ ${MODSTAT} -n cdev
+
+install:
+
+.include <bsd.prog.mk>
diff --git a/share/examples/kld/cdev/test/testcdev.c b/share/examples/kld/cdev/test/testcdev.c
new file mode 100644
index 000000000000..55205ac9b73e
--- /dev/null
+++ b/share/examples/kld/cdev/test/testcdev.c
@@ -0,0 +1,125 @@
+/* 08 Nov 1998*/
+/*-
+ * testmisc.c
+ *
+ * Test program to call the sample loaded kld device driver.
+ *
+ * 05 Jun 93 Rajesh Vaidheeswarran Original
+ *
+ *
+ * SPDX-License-Identifier: BSD-4-Clause
+ *
+ * Copyright (c) 1993 Rajesh Vaidheeswarran.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Rajesh Vaidheeswarran.
+ * 4. The name Rajesh Vaidheeswarran may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY RAJESH VAIDHEESWARRAN ``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 RAJESH VAIDHEESWARRAN BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Copyright (c) 1993 Terrence R. Lambert.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Terrence R. Lambert.
+ * 4. The name Terrence R. Lambert may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/types.h>
+#include <sys/ioccom.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <string.h>
+#include <unistd.h>
+
+#define CDEV_IOCTL1 _IOR('C', 1, u_int)
+#define CDEV_DEVICE "cdev"
+
+static char writestr[] = "Hello kernel!";
+static char buf[512+1];
+
+int
+main(int argc __unused, char *argv[] __unused)
+{
+ int kernel_fd;
+ int one;
+ int len;
+
+ if ((kernel_fd = open("/dev/" CDEV_DEVICE, O_RDWR)) == -1) {
+ perror("/dev/" CDEV_DEVICE);
+ exit(1);
+ }
+
+ /* Send ioctl */
+ if (ioctl(kernel_fd, CDEV_IOCTL1, &one) == -1) {
+ perror("CDEV_IOCTL1");
+ } else {
+ printf( "Sent ioctl CDEV_IOCTL1 to device %s%s\n", _PATH_DEV, CDEV_DEVICE);
+ }
+
+ len = strlen(writestr) + 1;
+
+ /* Write operation */
+ if (write(kernel_fd, writestr, len) == -1) {
+ perror("write()");
+ } else {
+ printf("Written \"%s\" string to device /dev/" CDEV_DEVICE "\n", writestr);
+ }
+
+ /* Read operation */
+ if (read(kernel_fd, buf, len) == -1) {
+ perror("read()");
+ } else {
+ printf("Read \"%s\" string from device /dev/" CDEV_DEVICE "\n", buf);
+ }
+
+ exit(0);
+}
diff --git a/share/examples/kld/dyn_sysctl/Makefile b/share/examples/kld/dyn_sysctl/Makefile
new file mode 100644
index 000000000000..0dffd9c8e7b0
--- /dev/null
+++ b/share/examples/kld/dyn_sysctl/Makefile
@@ -0,0 +1,7 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/${KMOD}
+SRCS = dyn_sysctl.c
+KMOD = dyn_sysctl
+
+.include <bsd.kmod.mk>
diff --git a/share/examples/kld/dyn_sysctl/README b/share/examples/kld/dyn_sysctl/README
new file mode 100644
index 000000000000..054a6e2328f7
--- /dev/null
+++ b/share/examples/kld/dyn_sysctl/README
@@ -0,0 +1,6 @@
+This example module creates partially overlapping subtrees to demonstrate
+reference counting. It also contains example of attaching a subtree to the
+wrong place, i.e. to a dynamic oid that could belong to someone else.
+The framework should deal with this case gracefully.
+
+Andrzej Bialecki <abial@freebsd.org>
diff --git a/share/examples/kld/dyn_sysctl/dyn_sysctl.c b/share/examples/kld/dyn_sysctl/dyn_sysctl.c
new file mode 100644
index 000000000000..b6d390bb9583
--- /dev/null
+++ b/share/examples/kld/dyn_sysctl/dyn_sysctl.c
@@ -0,0 +1,167 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2000 Andrzej Bialecki <abial@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/kernel.h>
+
+
+/* Some example data */
+static long a = 100;
+static int b = 200;
+static char *c = "hi there from dyn_sysctl";
+static struct sysctl_oid *a_root, *a_root1, *b_root;
+static struct sysctl_ctx_list clist, clist1, clist2;
+
+static int
+sysctl_dyn_sysctl_test(SYSCTL_HANDLER_ARGS)
+{
+ char *buf = "let's produce some text...";
+
+ return (sysctl_handle_string(oidp, buf, strlen(buf), req));
+}
+
+/*
+ * The function called at load/unload.
+ */
+static int
+load(module_t mod, int cmd, void *arg)
+{
+ int error;
+
+ error = 0;
+ switch (cmd) {
+ case MOD_LOAD:
+ /* Initialize the contexts */
+ printf("Initializing contexts and creating subtrees.\n\n");
+ sysctl_ctx_init(&clist);
+ sysctl_ctx_init(&clist1);
+ sysctl_ctx_init(&clist2);
+ /*
+ * Create two partially overlapping subtrees, belonging
+ * to different contexts.
+ */
+ printf("TREE ROOT NAME\n");
+ a_root = SYSCTL_ADD_ROOT_NODE(&clist,
+ OID_AUTO, "dyn_sysctl", CTLFLAG_RW, 0,
+ "dyn_sysctl root node");
+ a_root = SYSCTL_ADD_ROOT_NODE(&clist1,
+ OID_AUTO, "dyn_sysctl", CTLFLAG_RW, 0,
+ "dyn_sysctl root node");
+ if (a_root == NULL) {
+ printf("SYSCTL_ADD_NODE failed!\n");
+ return (EINVAL);
+ }
+ SYSCTL_ADD_LONG(&clist, SYSCTL_CHILDREN(a_root),
+ OID_AUTO, "long_a", CTLFLAG_RW, &a, "just to try");
+ SYSCTL_ADD_INT(&clist, SYSCTL_CHILDREN(a_root),
+ OID_AUTO, "int_b", CTLFLAG_RW, &b, 0, "just to try 1");
+ a_root1 = SYSCTL_ADD_NODE(&clist, SYSCTL_CHILDREN(a_root),
+ OID_AUTO, "nextlevel", CTLFLAG_RD, 0, "one level down");
+ SYSCTL_ADD_STRING(&clist, SYSCTL_CHILDREN(a_root1),
+ OID_AUTO, "string_c", CTLFLAG_RD, c, 0, "just to try 2");
+ printf("1. (%p) / dyn_sysctl\n", &clist);
+
+ /* Add a subtree under already existing category */
+ a_root1 = SYSCTL_ADD_NODE(&clist, SYSCTL_STATIC_CHILDREN(_kern),
+ OID_AUTO, "dyn_sysctl", CTLFLAG_RW, 0, "dyn_sysctl root node");
+ if (a_root1 == NULL) {
+ printf("SYSCTL_ADD_NODE failed!\n");
+ return (EINVAL);
+ }
+ SYSCTL_ADD_PROC(&clist, SYSCTL_CHILDREN(a_root1),
+ OID_AUTO, "procedure", CTLTYPE_STRING | CTLFLAG_RD,
+ NULL, 0, sysctl_dyn_sysctl_test, "A",
+ "I can be here, too");
+ printf(" (%p) /kern dyn_sysctl\n", &clist);
+
+ /* Overlap second tree with the first. */
+ b_root = SYSCTL_ADD_NODE(&clist1, SYSCTL_CHILDREN(a_root),
+ OID_AUTO, "nextlevel", CTLFLAG_RD, 0, "one level down");
+ SYSCTL_ADD_STRING(&clist1, SYSCTL_CHILDREN(b_root),
+ OID_AUTO, "string_c1", CTLFLAG_RD, c, 0, "just to try 2");
+ printf("2. (%p) / dyn_sysctl (overlapping #1)\n", &clist1);
+
+ /*
+ * And now do something stupid. Connect another subtree to
+ * dynamic oid.
+ * WARNING: this is an example of WRONG use of dynamic sysctls.
+ */
+ b_root=SYSCTL_ADD_NODE(&clist2, SYSCTL_CHILDREN(a_root1),
+ OID_AUTO, "bad", CTLFLAG_RW, 0, "dependent node");
+ SYSCTL_ADD_STRING(&clist2, SYSCTL_CHILDREN(b_root),
+ OID_AUTO, "string_c", CTLFLAG_RD, c, 0, "shouldn't panic");
+ printf("3. (%p) /kern/dyn_sysctl bad (WRONG!)\n", &clist2);
+ break;
+ case MOD_UNLOAD:
+ printf("1. Try to free ctx1 (%p): ", &clist);
+ if (sysctl_ctx_free(&clist) != 0)
+ printf("failed: expected. Need to remove ctx3 first.\n");
+ else
+ printf("HELP! sysctl_ctx_free(%p) succeeded. EXPECT PANIC!!!\n", &clist);
+ printf("2. Try to free ctx3 (%p): ", &clist2);
+ if (sysctl_ctx_free(&clist2) != 0) {
+ printf("sysctl_ctx_free(%p) failed!\n", &clist2);
+ /* Remove subtree forcefully... */
+ sysctl_remove_oid(b_root, 1, 1);
+ printf("sysctl_remove_oid(%p) succeeded\n", b_root);
+ } else
+ printf("Ok\n");
+ printf("3. Try to free ctx1 (%p) again: ", &clist);
+ if (sysctl_ctx_free(&clist) != 0) {
+ printf("sysctl_ctx_free(%p) failed!\n", &clist);
+ /* Remove subtree forcefully... */
+ sysctl_remove_oid(a_root1, 1, 1);
+ printf("sysctl_remove_oid(%p) succeeded\n", a_root1);
+ } else
+ printf("Ok\n");
+ printf("4. Try to free ctx2 (%p): ", &clist1);
+ if (sysctl_ctx_free(&clist1) != 0) {
+ printf("sysctl_ctx_free(%p) failed!\n", &clist1);
+ /* Remove subtree forcefully... */
+ sysctl_remove_oid(a_root, 1, 1);
+ } else
+ printf("Ok\n");
+ break;
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+ return (error);
+}
+
+static moduledata_t mod_data = {
+ "dyn_sysctl",
+ load,
+ 0
+};
+
+DECLARE_MODULE(dyn_sysctl, mod_data, SI_SUB_EXEC, SI_ORDER_ANY);
diff --git a/share/examples/kld/firmware/Makefile b/share/examples/kld/firmware/Makefile
new file mode 100644
index 000000000000..b4b144a7669d
--- /dev/null
+++ b/share/examples/kld/firmware/Makefile
@@ -0,0 +1,6 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/firmware
+SUBDIR= fwimage fwconsumer
+
+.include <bsd.subdir.mk>
diff --git a/share/examples/kld/firmware/README b/share/examples/kld/firmware/README
new file mode 100644
index 000000000000..473245a8e2ae
--- /dev/null
+++ b/share/examples/kld/firmware/README
@@ -0,0 +1,17 @@
+
+This is a simple example of the firmware(9) system. It consists of two
+parts:
+
+1) fwimage
+ This is the firmware image (the ascii art of beastie from the boot
+ menu). The Makefile lists the firmware file "firmware.img" and the
+ short handle for this firmware image "beastie".
+ Note that the module is called "beastie" as well so that it can be
+ loaded automatically if requested.
+
+2) fwconsumer
+ This module tries to get the a firmware image called "beastie",
+ checks if the data is '\0'-terminated and prints it to the console.
+ It keeps a reference to the firmware until it is unloaded.
+
+This is mainly to demonstrate how to construct firmware image modules.
diff --git a/share/examples/kld/firmware/fwconsumer/Makefile b/share/examples/kld/firmware/fwconsumer/Makefile
new file mode 100644
index 000000000000..b29684999124
--- /dev/null
+++ b/share/examples/kld/firmware/fwconsumer/Makefile
@@ -0,0 +1,7 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/fwconsumer
+KMOD= fw_consumer
+SRCS= fw_consumer.c
+
+.include <bsd.kmod.mk>
diff --git a/share/examples/kld/firmware/fwconsumer/fw_consumer.c b/share/examples/kld/firmware/fwconsumer/fw_consumer.c
new file mode 100644
index 000000000000..8d749fed65df
--- /dev/null
+++ b/share/examples/kld/firmware/fwconsumer/fw_consumer.c
@@ -0,0 +1,77 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2006, Max Laier <mlaier@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+#include <sys/linker.h>
+#include <sys/firmware.h>
+#include <sys/proc.h>
+#include <sys/module.h>
+
+static const struct firmware *fp;
+
+static int
+fw_consumer_modevent(module_t mod, int type, void *unused)
+{
+ switch (type) {
+ case MOD_LOAD:
+ fp = firmware_get("beastie");
+
+ if (fp == NULL)
+ return (ENOENT);
+
+ if (((const char *)fp->data)[fp->datasize - 1] != '\0') {
+ firmware_put(fp, FIRMWARE_UNLOAD);
+ return (EINVAL);
+ }
+ printf("%s", (const char *)fp->data);
+
+ return (0);
+ case MOD_UNLOAD:
+ printf("Bye!\n");
+
+ if (fp != NULL) {
+ printf("%s", (const char *)fp->data);
+ firmware_put(fp, FIRMWARE_UNLOAD);
+ }
+
+ return (0);
+ }
+ return (EINVAL);
+}
+
+static moduledata_t fw_consumer_mod = {
+ "fw_consumer",
+ fw_consumer_modevent,
+ 0
+};
+DECLARE_MODULE(fw_consumer, fw_consumer_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
+MODULE_VERSION(fw_consumer, 1);
+MODULE_DEPEND(fw_consumer, firmware, 1, 1, 1);
diff --git a/share/examples/kld/firmware/fwimage/Makefile b/share/examples/kld/firmware/fwimage/Makefile
new file mode 100644
index 000000000000..1e0e3ff3ca93
--- /dev/null
+++ b/share/examples/kld/firmware/fwimage/Makefile
@@ -0,0 +1,12 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/fwimage
+KMOD= beastie
+FIRMWS= firmware.img:beastie
+
+CLEANFILES= firmware.img
+
+firmware.img: firmware.img.uu
+ uudecode -p ${.ALLSRC} > ${.TARGET}
+
+.include <bsd.kmod.mk>
diff --git a/share/examples/kld/firmware/fwimage/firmware.img.uu b/share/examples/kld/firmware/fwimage/firmware.img.uu
new file mode 100644
index 000000000000..075877e0bcb3
--- /dev/null
+++ b/share/examples/kld/firmware/fwimage/firmware.img.uu
@@ -0,0 +1,15 @@
+begin 644 firmware.img
+M("`@("`@("`@("`@("`L("`@("`@("`L"B`@("`@("`@("`@("`O*"`@("`@
+M("`@*0H@("`@("`@("`@("`@7"!<7U]?("`@+R!\"B`@("`@("`@("`@("`O
+M+2!?("`M+R`@)PH@("`@("`@("`@("`H+UPO(%P@7"`@("]<"B`@("`@("`@
+M("`@("\@+R`@('P@("`@(%P*("`@("`@("`@("`@3R!/("`@*2`O("`@('P*
+M("`@("`@("`@("`@+5XM+2<\("`@("`G"B`@("`@("`@("`@*%\N*2`@7R`@
+M*2`@("\*("`@("`@("`@("`@+E]?7R\@("`@+PH@("`@("`@("`@("`@("TM
+M+2TM)R`O"B`\+2TM+2X@("`@(%]?("\@7U\@("!<"B`\+2TM+7P]/3T]3RDI
+M*3T]*2!<*2`O/3T]/0H@/"TM+2TG("`@("TM)R`N7U\L)R!<"B`@("`@("`@
+M("`@("`@?"`@("`@("`@?`H@("`@("`@("`@("`@("!<("`@("`@("\@("`@
+M("`@+UP*("`@("`@("`@(%]?7U]?7R@@*%\@("\@7%]?7U]?7R\*("`@("`@
+M("`L)R`@+"TM+2TM)R`@('P*("`@("`@("`M+7M?7U]?7U]?7U]?*2`@0V]P
+@>7)I9VAT("AC*2`R,#`S(%-C;W1T($QO;F<*````````
+`
+end
diff --git a/share/examples/kld/khelp/Makefile b/share/examples/kld/khelp/Makefile
new file mode 100644
index 000000000000..7cbaa79ceda6
--- /dev/null
+++ b/share/examples/kld/khelp/Makefile
@@ -0,0 +1,12 @@
+
+.include <bsd.own.mk>
+
+# Change if the src tree you are compiling for is not in /usr/src
+#SYSDIR=/usr/src/sys
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/khelp
+KMOD= h_example
+SRCS= h_example.c
+
+.include <bsd.kmod.mk>
diff --git a/share/examples/kld/khelp/README b/share/examples/kld/khelp/README
new file mode 100644
index 000000000000..af201809864c
--- /dev/null
+++ b/share/examples/kld/khelp/README
@@ -0,0 +1,5 @@
+
+An example Khelp module which uses the helper hook points available in the TCP
+stack to calculate a per-connection count of inbound and outbound packets when
+the connection is in the established state. The code is verbosely documented in
+an attempt to explain how everything fits together.
diff --git a/share/examples/kld/khelp/h_example.c b/share/examples/kld/khelp/h_example.c
new file mode 100644
index 000000000000..fea7826a1fb4
--- /dev/null
+++ b/share/examples/kld/khelp/h_example.c
@@ -0,0 +1,153 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2010-2011 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed at the Centre for Advanced Internet
+ * Architectures, Swinburne University of Technology, Melbourne, Australia by
+ * Lawrence Stewart under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This example Khelp module uses the helper hook points available in the TCP
+ * stack to calculate a per-connection count of inbound and outbound packets
+ * when the connection is in the established state. The code is verbosely
+ * documented in an attempt to explain how everything fits together.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/hhook.h>
+#include <sys/khelp.h>
+#include <sys/module.h>
+#include <sys/module_khelp.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+
+#include <netinet/tcp_var.h>
+
+#include <vm/uma.h>
+
+/*
+ * Function prototype for our helper hook (man 9 hhook) compatible hook
+ * function.
+ */
+static int example_hook(int hhook_type, int hhook_id, void *udata,
+ void *ctx_data, void *hdata, struct osd *hosd);
+
+/*
+ * Our per-connection persistent data storage struct.
+ */
+struct example {
+ uint32_t est_in_count;
+ uint32_t est_out_count;
+};
+
+/*
+ * Fill in the required bits of our module's struct helper (defined in
+ * <sys/module_khelp.h>).
+ *
+ * - Our helper will be storing persistent state for each TCP connection, so we
+ * request the use the Object Specific Data (OSD) feature from the framework by
+ * setting the HELPER_NEEDS_OSD flag.
+ *
+ * - Our helper is related to the TCP subsystem, so tell the Khelp framework
+ * this by setting an appropriate class for the module. When a new TCP
+ * connection is created, the Khelp framework takes care of associating helper
+ * modules of the appropriate class with the new connection.
+ */
+struct helper example_helper = {
+ .h_flags = HELPER_NEEDS_OSD,
+ .h_classes = HELPER_CLASS_TCP
+};
+
+/*
+ * Set which helper hook points our module wants to hook by creating an array of
+ * hookinfo structs (defined in <sys/hhook.h>). We hook the TCP established
+ * inbound/outbound hook points (TCP hhook points are defined in
+ * <netinet/tcp_var.h>) with our example_hook() function. We don't require a user
+ * data pointer to be passed to our hook function when called, so we set it to
+ * NULL.
+ */
+struct hookinfo example_hooks[] = {
+ {
+ .hook_type = HHOOK_TYPE_TCP,
+ .hook_id = HHOOK_TCP_EST_IN,
+ .hook_udata = NULL,
+ .hook_func = &example_hook
+ },
+ {
+ .hook_type = HHOOK_TYPE_TCP,
+ .hook_id = HHOOK_TCP_EST_OUT,
+ .hook_udata = NULL,
+ .hook_func = &example_hook
+ }
+};
+
+/*
+ * Very simple helper hook function. Here's a quick run through the arguments:
+ *
+ * - hhook_type and hhook_id are useful if you use a single function with many
+ * hook points and want to know which hook point called the function.
+ *
+ * - udata will be NULL, because we didn't elect to pass a pointer in either of
+ * the hookinfo structs we instantiated above in the example_hooks array.
+ *
+ * - ctx_data contains context specific data from the hook point call site. The
+ * data type passed is subsystem dependent. In the case of TCP, the hook points
+ * pass a pointer to a "struct tcp_hhook_data" (defined in <netinet/tcp_var.h>).
+ *
+ * - hdata is a pointer to the persistent per-object storage for our module. The
+ * pointer is allocated automagically by the Khelp framework when the connection
+ * is created, and comes from a dedicated UMA zone. It will never be NULL.
+ *
+ * - hosd can be used with the Khelp framework's khelp_get_osd() function to
+ * access data belonging to a different Khelp module.
+ */
+static int
+example_hook(int hhook_type, int hhook_id, void *udata, void *ctx_data,
+ void *hdata, struct osd *hosd)
+{
+ struct example *data;
+
+ data = hdata;
+
+ if (hhook_id == HHOOK_TCP_EST_IN)
+ data->est_in_count++;
+ else if (hhook_id == HHOOK_TCP_EST_OUT)
+ data->est_out_count++;
+
+ return (0);
+}
+
+/*
+ * We use a convenient macro which handles registering our module with the Khelp
+ * framework. Note that Khelp modules which set the HELPER_NEEDS_OSD flag (i.e.
+ * require persistent per-object storage) must use the KHELP_DECLARE_MOD_UMA()
+ * macro. If you don't require per-object storage, use the KHELP_DECLARE_MOD()
+ * macro instead.
+ */
+KHELP_DECLARE_MOD_UMA(example, &example_helper, example_hooks, 1,
+ sizeof(struct example), NULL, NULL);
diff --git a/share/examples/kld/random_adaptor/Makefile b/share/examples/kld/random_adaptor/Makefile
new file mode 100644
index 000000000000..c391da795e89
--- /dev/null
+++ b/share/examples/kld/random_adaptor/Makefile
@@ -0,0 +1,7 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/${KMOD}
+KMOD= random_adaptor_example
+SRCS= ${KMOD}.c
+
+.include <bsd.kmod.mk>
diff --git a/share/examples/kld/random_adaptor/random_adaptor_example.c b/share/examples/kld/random_adaptor/random_adaptor_example.c
new file mode 100644
index 000000000000..6dd3321d1286
--- /dev/null
+++ b/share/examples/kld/random_adaptor/random_adaptor_example.c
@@ -0,0 +1,124 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2013 Arthur Mesh <arthurmesh@gmail.com>
+ * 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
+ * in this position and unchanged.
+ * 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 ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/random.h>
+#include <sys/systm.h>
+
+#include <dev/random/randomdev.h>
+#include <dev/random/randomdev_soft.h>
+#include <dev/random/random_adaptors.h>
+#include <dev/random/live_entropy_sources.h>
+
+static void live_random_example_init(void);
+static void live_random_example_deinit(void);
+static u_int live_random_example_read(void *, u_int);
+
+struct random_adaptor live_random_example = {
+ .les_ident = "Example RNG",
+ .les_source = RANDOM_PURE_BOGUS, /* Make sure this is in
+ * sys/random.h and is unique */
+ .les_read = live_random_example_read,
+};
+
+/*
+ * Used under the license provided @ http://xkcd.com/221/
+ * http://creativecommons.org/licenses/by-nc/2.5/
+ */
+static uint8_t
+getRandomNumber(void)
+{
+ return 4; /* chosen by fair dice roll, guaranteed to be random */
+}
+
+static void
+live_random_example_init(void)
+{
+
+ /* Do initialisation stuff here */
+}
+
+static void
+live_random_example_deinit(void)
+{
+
+ /* Do de-initialisation stuff here */
+}
+
+/* get <c> bytes of random stuff into <buf>. You may presume
+ * that <c> is a multiple of 2^n, with n>=3. A typical value
+ * is c=16.
+ */
+static u_int
+live_random_example_read(void *buf, u_int c)
+{
+ uint8_t *b;
+ int count;
+
+ b = buf;
+
+ for (count = 0; count < c; count++)
+ b[count] = getRandomNumber();
+
+ /* printf("returning %d bytes of pure randomness\n", c); */
+ return (c);
+}
+
+/* ARGSUSED */
+static int
+live_random_example_modevent(module_t mod __unused, int type, void *unused __unused)
+{
+ int error = 0;
+
+ switch (type) {
+ case MOD_LOAD:
+ live_entropy_source_register(&live_random_example);
+ break;
+
+ case MOD_UNLOAD:
+ live_entropy_source_deregister(&live_random_example);
+ break;
+
+ case MOD_SHUTDOWN:
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+DEV_MODULE(live_random_example, live_random_example_modevent, NULL);
+MODULE_VERSION(live_random_example, 1);
+MODULE_DEPEND(live_random_example, randomdev, 1, 1, 1);
diff --git a/share/examples/kld/syscall/Makefile b/share/examples/kld/syscall/Makefile
new file mode 100644
index 000000000000..efae887771e2
--- /dev/null
+++ b/share/examples/kld/syscall/Makefile
@@ -0,0 +1,8 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/syscall
+SUBDIR= module test
+
+load unload: _SUBDIR
+
+.include <bsd.subdir.mk>
diff --git a/share/examples/kld/syscall/module/Makefile b/share/examples/kld/syscall/module/Makefile
new file mode 100644
index 000000000000..760825e4d52a
--- /dev/null
+++ b/share/examples/kld/syscall/module/Makefile
@@ -0,0 +1,8 @@
+# Makefile for building the sample syscall module
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/${KMOD}
+KMOD= syscall
+SRCS= syscall.c
+
+.include <bsd.kmod.mk>
diff --git a/share/examples/kld/syscall/module/syscall.c b/share/examples/kld/syscall/module/syscall.c
new file mode 100644
index 000000000000..3f6051d03777
--- /dev/null
+++ b/share/examples/kld/syscall/module/syscall.c
@@ -0,0 +1,83 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999 Assar Westerlund
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/module.h>
+#include <sys/sysproto.h>
+#include <sys/sysent.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+
+/*
+ * The function for implementing the syscall.
+ */
+static int
+hello(struct thread *td, void *arg)
+{
+
+ printf("hello kernel\n");
+ return (0);
+}
+
+/*
+ * The `sysent' for the new syscall
+ */
+static struct sysent hello_sysent = {
+ .sy_narg = 0,
+ .sy_call = hello
+};
+
+/*
+ * The offset in sysent where the syscall is allocated.
+ */
+static int offset = NO_SYSCALL;
+
+/*
+ * The function called at load/unload.
+ */
+static int
+load(struct module *module, int cmd, void *arg)
+{
+ int error = 0;
+
+ switch (cmd) {
+ case MOD_LOAD :
+ printf("syscall loaded at %d\n", offset);
+ break;
+ case MOD_UNLOAD :
+ printf("syscall unloaded from %d\n", offset);
+ break;
+ default :
+ error = EOPNOTSUPP;
+ break;
+ }
+ return (error);
+}
+
+SYSCALL_MODULE(syscall, &offset, &hello_sysent, load, NULL);
diff --git a/share/examples/kld/syscall/test/Makefile b/share/examples/kld/syscall/test/Makefile
new file mode 100644
index 000000000000..d14cd895c15d
--- /dev/null
+++ b/share/examples/kld/syscall/test/Makefile
@@ -0,0 +1,9 @@
+# Makefile for simple caller of syscall
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/kld/test
+PROG= call
+MAN=
+WARNS?= 5
+
+.include <bsd.prog.mk>
diff --git a/share/examples/kld/syscall/test/call.c b/share/examples/kld/syscall/test/call.c
new file mode 100644
index 000000000000..e62f8f27f1dd
--- /dev/null
+++ b/share/examples/kld/syscall/test/call.c
@@ -0,0 +1,51 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999 Assar Westerlund
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/module.h>
+#include <sys/syscall.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc __unused, char **argv __unused)
+{
+ int modid, syscall_num;
+ struct module_stat stat;
+
+ stat.version = sizeof(stat);
+ if ((modid = modfind("sys/syscall")) == -1)
+ err(1, "modfind");
+ if (modstat(modid, &stat) != 0)
+ err(1, "modstat");
+ syscall_num = stat.data.intval;
+ return syscall (syscall_num);
+}
diff --git a/share/examples/libifconfig/Makefile b/share/examples/libifconfig/Makefile
new file mode 100644
index 000000000000..954206116eaa
--- /dev/null
+++ b/share/examples/libifconfig/Makefile
@@ -0,0 +1,10 @@
+default:
+ $(CC) -Wall -fPIC -lifconfig -g -o example_setdescription setdescription.c
+ $(CC) -Wall -fPIC -lifconfig -g -o example_setmtu setmtu.c
+ $(CC) -Wall -fPIC -lifconfig -g -o example_ifdestroy ifdestroy.c
+ $(CC) -Wall -fPIC -lifconfig -g -o example_ifcreate ifcreate.c
+ $(CC) -Wall -fPIC -lifconfig -g -o example_ifcreatevlan ifcreatevlan.c
+ $(CC) -Wall -fPIC -lifconfig -g -o example_ifchanagevlan ifchanagevlan.c
+ $(CC) -Wall -fPIC -lifconfig -g -o example_status status.c
+clean:
+ rm -f example_*
diff --git a/share/examples/libifconfig/ifchangevlan.c b/share/examples/libifconfig/ifchangevlan.c
new file mode 100644
index 000000000000..18a7b6de638a
--- /dev/null
+++ b/share/examples/libifconfig/ifchangevlan.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017, Marie Helene Kvello-Aune
+ * 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,
+ * thislist 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 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 HOLDER 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 <err.h>
+#include <errno.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libifconfig.h>
+
+#include <net/if_vlan_var.h>
+
+int
+main(int argc, char *argv[])
+{
+ char *ifname, *parentif;
+ unsigned short vlantag;
+ const char *errstr;
+ ifconfig_handle_t *lifh;
+
+ if (argc != 4) {
+ errx(EINVAL, "Invalid number of arguments."
+ " Should provide exactly three arguments: "
+ "INTERFACE, PARENT_INTERFACE and VLAN_TAG.");
+ }
+
+ /* We have a static number of arguments. Therefore we can do it simple. */
+ ifname = strdup(argv[1]);
+ parentif = strdup(argv[2]);
+ vlantag = strtonum(argv[3], 0, USHRT_MAX, &errstr);
+
+ if (errstr != NULL) {
+ errx(1, "VLAN_TAG must be between 0 and %i.\n", USHRT_MAX);
+ }
+
+ printf("Interface: %s\nNew VLAN tag: %i\n", ifname, vlantag);
+
+ lifh = ifconfig_open();
+ if (lifh == NULL) {
+ errx(ENOMEM, "Failed to open libifconfig handle.");
+ return (-1);
+ }
+
+ if (ifconfig_set_vlantag(lifh, ifname, parentif, vlantag) == 0) {
+ printf("Successfully changed vlan tag.\n");
+ ifconfig_close(lifh);
+ lifh = NULL;
+ free(ifname);
+ free(parentif);
+ return (0);
+ }
+
+ switch (ifconfig_err_errtype(lifh)) {
+ case SOCKET:
+ warnx("couldn't create socket. This shouldn't happen.\n");
+ break;
+ case IOCTL:
+ if (ifconfig_err_ioctlreq(lifh) == SIOCGETVLAN) {
+ warnx("Target interface isn't a VLAN interface.\n");
+ }
+ if (ifconfig_err_ioctlreq(lifh) == SIOCSETVLAN) {
+ warnx(
+ "Couldn't change VLAN properties of interface.\n");
+ }
+ break;
+ default:
+ warnx(
+ "This is a thorough example accommodating for temporary"
+ " 'not implemented yet' errors. That's likely what happened"
+ " now. If not, your guess is as good as mine. ;)"
+ " Error code: %d\n", ifconfig_err_errno(
+ lifh));
+ break;
+ }
+
+ ifconfig_close(lifh);
+ lifh = NULL;
+ free(ifname);
+ free(parentif);
+ return (-1);
+}
diff --git a/share/examples/libifconfig/ifcreate.c b/share/examples/libifconfig/ifcreate.c
new file mode 100644
index 000000000000..ae1e565d2ab7
--- /dev/null
+++ b/share/examples/libifconfig/ifcreate.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016-2017, Marie Helene Kvello-Aune
+ * 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,
+ * thislist 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 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 HOLDER 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 <err.h>
+#include <errno.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libifconfig.h>
+
+
+int
+main(int argc, char *argv[])
+{
+ char *ifname, *ifactualname;
+ ifconfig_handle_t *lifh;
+
+ if (argc != 2) {
+ errx(EINVAL, "Invalid number of arguments."
+ " Only one argument is accepted, and it should be the name"
+ " of the interface to be created.");
+ }
+
+ /* We have a static number of arguments. Therefore we can do it simple. */
+ ifname = strdup(argv[1]);
+
+ printf("Requested interface name: %s\n", ifname);
+
+ lifh = ifconfig_open();
+ if (lifh == NULL) {
+ errx(ENOMEM, "Failed to open libifconfig handle.");
+ return (-1);
+ }
+
+ if (ifconfig_create_interface(lifh, ifname, &ifactualname) == 0) {
+ printf("Successfully created interface '%s'\n", ifactualname);
+ ifconfig_close(lifh);
+ lifh = NULL;
+ free(ifname);
+ free(ifactualname);
+ return (0);
+ }
+
+ switch (ifconfig_err_errtype(lifh)) {
+ case SOCKET:
+ warnx("couldn't create socket. This shouldn't happen.\n");
+ break;
+ case IOCTL:
+ if (ifconfig_err_ioctlreq(lifh) == SIOCIFCREATE2) {
+ warnx(
+ "Failed to create interface (SIOCIFCREATE2)\n");
+ }
+ break;
+ default:
+ warnx(
+ "This is a thorough example accommodating for temporary"
+ " 'not implemented yet' errors. That's likely what happened"
+ " now. If not, your guess is as good as mine. ;)"
+ " Error code: %d\n", ifconfig_err_errno(
+ lifh));
+ break;
+ }
+
+ ifconfig_close(lifh);
+ lifh = NULL;
+ free(ifname);
+ free(ifactualname);
+ return (-1);
+}
diff --git a/share/examples/libifconfig/ifcreatevlan.c b/share/examples/libifconfig/ifcreatevlan.c
new file mode 100644
index 000000000000..b41dd63bfe82
--- /dev/null
+++ b/share/examples/libifconfig/ifcreatevlan.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017, Marie Helene Kvello-Aune
+ * 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,
+ * thislist 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 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 HOLDER 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 <err.h>
+#include <errno.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libifconfig.h>
+
+
+int
+main(int argc, char *argv[])
+{
+ char *parentif, *ifactualname;
+ unsigned short vlantag;
+ const char *errstr;
+ ifconfig_handle_t *lifh;
+
+ if (argc != 3) {
+ errx(EINVAL, "Invalid number of arguments."
+ " Should provide exactly two arguments: "
+ "PARENT_INTERFACE and VLAN_TAG.");
+ }
+
+ /* We have a static number of arguments. Therefore we can do it simple. */
+ parentif = strdup(argv[1]);
+ vlantag = strtonum(argv[2], 0, USHRT_MAX, &errstr);
+
+ if (errstr != NULL) {
+ errx(1, "VLAN_TAG must be between 0 and %i.\n", USHRT_MAX);
+ }
+
+ printf("Parent interface: %s\nVLAN tag: %i\n", parentif, vlantag);
+
+ lifh = ifconfig_open();
+ if (lifh == NULL) {
+ errx(ENOMEM, "Failed to open libifconfig handle.");
+ return (-1);
+ }
+
+ if (ifconfig_create_interface_vlan(lifh, "vlan", &ifactualname,
+ parentif, vlantag) == 0) {
+ printf("Successfully created interface '%s'\n", ifactualname);
+ ifconfig_close(lifh);
+ lifh = NULL;
+ free(parentif);
+ free(ifactualname);
+ return (0);
+ }
+
+ switch (ifconfig_err_errtype(lifh)) {
+ case SOCKET:
+ warnx("couldn't create socket. This shouldn't happen.\n");
+ break;
+ case IOCTL:
+ if (ifconfig_err_ioctlreq(lifh) == SIOCIFCREATE2) {
+ warnx(
+ "Failed to create interface (SIOCIFCREATE2)\n");
+ }
+ break;
+ default:
+ warnx(
+ "This is a thorough example accommodating for temporary"
+ " 'not implemented yet' errors. That's likely what happened"
+ " now. If not, your guess is as good as mine. ;)"
+ " Error code: %d\n", ifconfig_err_errno(
+ lifh));
+ break;
+ }
+
+ ifconfig_close(lifh);
+ lifh = NULL;
+ free(parentif);
+ free(ifactualname);
+ return (-1);
+}
diff --git a/share/examples/libifconfig/ifdestroy.c b/share/examples/libifconfig/ifdestroy.c
new file mode 100644
index 000000000000..d4f3d3ac6e6f
--- /dev/null
+++ b/share/examples/libifconfig/ifdestroy.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2016-2017, Marie Helene Kvello-Aune
+ * 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,
+ * thislist 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 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 HOLDER 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 <err.h>
+#include <errno.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libifconfig.h>
+
+
+int
+main(int argc, char *argv[])
+{
+ char *ifname;
+ ifconfig_handle_t *lifh;
+
+ if (argc != 2) {
+ errx(EINVAL, "Invalid number of arguments."
+ " Only one argument is accepted, and it should be the name"
+ " of the interface to be destroyed.");
+ }
+
+ /* We have a static number of arguments. Therefore we can do it simple. */
+ ifname = strdup(argv[1]);
+
+ printf("Interface name: %s\n", ifname);
+
+ lifh = ifconfig_open();
+ if (lifh == NULL) {
+ errx(ENOMEM, "Failed to open libifconfig handle.");
+ return (-1);
+ }
+
+ if (ifconfig_destroy_interface(lifh, ifname) == 0) {
+ printf("Successfully destroyed interface '%s'.", ifname);
+ ifconfig_close(lifh);
+ lifh = NULL;
+ free(ifname);
+ return (0);
+ }
+
+ switch (ifconfig_err_errtype(lifh)) {
+ case SOCKET:
+ warnx("couldn't create socket. This shouldn't happen.\n");
+ break;
+ case IOCTL:
+ if (ifconfig_err_ioctlreq(lifh) == SIOCIFDESTROY) {
+ warnx(
+ "Failed to destroy interface (SIOCIFDESTROY)\n");
+ }
+ break;
+ default:
+ warnx(
+ "Should basically never end up here in this example.\n");
+ break;
+ }
+
+ ifconfig_close(lifh);
+ lifh = NULL;
+ free(ifname);
+ return (-1);
+}
diff --git a/share/examples/libifconfig/setdescription.c b/share/examples/libifconfig/setdescription.c
new file mode 100644
index 000000000000..5fde440b4bee
--- /dev/null
+++ b/share/examples/libifconfig/setdescription.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016-2017, Marie Helene Kvello-Aune
+ * 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,
+ * thislist 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 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 HOLDER 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 <arpa/inet.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libifconfig.h>
+
+
+int
+main(int argc, char *argv[])
+{
+ char *ifname, *ifdescr, *curdescr;
+ ifconfig_handle_t *lifh;
+
+ if (argc != 3) {
+ errx(EINVAL, "Invalid number of arguments."
+ " First argument should be interface name, second argument"
+ " should be the description to set.");
+ }
+
+ /* We have a static number of arguments. Therefore we can do it simple. */
+ ifname = strdup(argv[1]);
+ ifdescr = strdup(argv[2]);
+ curdescr = NULL;
+
+ printf("Interface name: %s\n", ifname);
+
+ lifh = ifconfig_open();
+ if (lifh == NULL) {
+ errx(ENOMEM, "Failed to open libifconfig handle.");
+ return (-1);
+ }
+
+ if (ifconfig_get_description(lifh, ifname, &curdescr) == 0) {
+ printf("Old description: %s\n", curdescr);
+ }
+
+ printf("New description: %s\n\n", ifdescr);
+
+ if (ifconfig_set_description(lifh, ifname, ifdescr) == 0) {
+ printf("New description successfully set.\n");
+ } else {
+ switch (ifconfig_err_errtype(lifh)) {
+ case SOCKET:
+ err(ifconfig_err_errno(lifh), "Socket error");
+ break;
+ case IOCTL:
+ err(ifconfig_err_errno(
+ lifh), "IOCTL(%lu) error",
+ ifconfig_err_ioctlreq(lifh));
+ break;
+ default:
+ err(ifconfig_err_errno(lifh), "Other error");
+ break;
+ }
+ }
+
+ free(ifname);
+ free(ifdescr);
+ free(curdescr);
+ ifname = NULL;
+ ifdescr = NULL;
+ curdescr = NULL;
+
+ ifconfig_close(lifh);
+ return (0);
+}
diff --git a/share/examples/libifconfig/setmtu.c b/share/examples/libifconfig/setmtu.c
new file mode 100644
index 000000000000..06417cb7fc5b
--- /dev/null
+++ b/share/examples/libifconfig/setmtu.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016-2017, Marie Helene Kvello-Aune
+ * 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,
+ * thislist 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 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 HOLDER 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 <err.h>
+#include <errno.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libifconfig.h>
+
+
+int
+main(int argc, char *argv[])
+{
+ char *ifname, *ptr;
+ int mtu;
+ ifconfig_handle_t *lifh;
+
+ if (argc != 3) {
+ errx(EINVAL, "Invalid number of arguments."
+ " First argument should be interface name, second argument"
+ " should be the MTU to set.");
+ }
+
+ /* We have a static number of arguments. Therefore we can do it simple. */
+ ifname = strdup(argv[1]);
+ mtu = (int)strtol(argv[2], &ptr, 10);
+
+ printf("Interface name: %s\n", ifname);
+ printf("New MTU: %d", mtu);
+
+ lifh = ifconfig_open();
+ if (lifh == NULL) {
+ errx(ENOMEM, "Failed to open libifconfig handle.");
+ return (-1);
+ }
+
+ if (ifconfig_set_mtu(lifh, ifname, mtu) == 0) {
+ printf("Successfully changed MTU of %s to %d\n", ifname, mtu);
+ ifconfig_close(lifh);
+ lifh = NULL;
+ free(ifname);
+ return (0);
+ }
+
+ switch (ifconfig_err_errtype(lifh)) {
+ case SOCKET:
+ warnx("couldn't create socket. This shouldn't happen.\n");
+ break;
+ case IOCTL:
+ if (ifconfig_err_ioctlreq(lifh) == SIOCSIFMTU) {
+ warnx("Failed to set MTU (SIOCSIFMTU)\n");
+ } else {
+ warnx(
+ "Failed to set MTU due to error in unexpected ioctl() call %lu. Error code: %i.\n",
+ ifconfig_err_ioctlreq(lifh),
+ ifconfig_err_errno(lifh));
+ }
+ break;
+ default:
+ warnx(
+ "Should basically never end up here in this example.\n");
+ break;
+ }
+
+ ifconfig_close(lifh);
+ lifh = NULL;
+ free(ifname);
+ return (-1);
+}
diff --git a/share/examples/libifconfig/status.c b/share/examples/libifconfig/status.c
new file mode 100644
index 000000000000..6f0eeb0b223b
--- /dev/null
+++ b/share/examples/libifconfig/status.c
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2017, 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,
+ * thislist 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 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 HOLDER 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/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <arpa/inet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_lagg.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/ip_carp.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <err.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libifconfig.h>
+
+static const char *carp_states[] = { CARP_STATES };
+
+static void
+print_carp(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
+{
+ struct carpreq carpr[CARP_MAXVHID];
+ int i;
+
+ if (ifconfig_carp_get_info(lifh, ifa->ifa_name, carpr, CARP_MAXVHID)) {
+ return; /* Probably not configured on this interface */
+ }
+ for (i = 0; i < carpr[0].carpr_count; i++) {
+ printf("\tcarp: %s vhid %d advbase %d advskew %d",
+ carp_states[carpr[i].carpr_state], carpr[i].carpr_vhid,
+ carpr[i].carpr_advbase, carpr[i].carpr_advskew);
+ printf("\n");
+ }
+}
+
+static void
+print_inet4_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
+{
+ struct ifconfig_inet_addr addr;
+ char addr_buf[NI_MAXHOST];
+
+ if (ifconfig_inet_get_addrinfo(lifh, ifa->ifa_name, ifa, &addr) != 0) {
+ return;
+ }
+
+ inet_ntop(AF_INET, &addr.sin->sin_addr, addr_buf, sizeof(addr_buf));
+ printf("\tinet %s", addr_buf);
+
+ if (addr.dst) {
+ printf(" --> %s", inet_ntoa(addr.dst->sin_addr));
+ }
+
+ printf(" netmask 0x%x ", ntohl(addr.netmask->sin_addr.s_addr));
+
+ if ((addr.broadcast != NULL) &&
+ (addr.broadcast->sin_addr.s_addr != 0)) {
+ printf("broadcast %s ", inet_ntoa(addr.broadcast->sin_addr));
+ }
+
+ if (addr.vhid != 0) {
+ printf("vhid %d ", addr.vhid);
+ }
+ printf("\n");
+}
+
+static void
+print_inet6_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
+{
+ struct ifconfig_inet6_addr addr;
+ char addr_buf[NI_MAXHOST];
+ struct timespec now;
+
+ /* Print the address */
+ if (ifconfig_inet6_get_addrinfo(lifh, ifa->ifa_name, ifa, &addr) != 0) {
+ err(1, "ifconfig_inet6_get_addrinfo");
+ }
+ if (0 != getnameinfo((struct sockaddr *)addr.sin6, addr.sin6->sin6_len,
+ addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST)) {
+ inet_ntop(AF_INET6, &addr.sin6->sin6_addr, addr_buf,
+ sizeof(addr_buf));
+ }
+ printf("\tinet6 %s", addr_buf);
+
+ if (addr.dstin6) {
+ inet_ntop(AF_INET6, addr.dstin6, addr_buf, sizeof(addr_buf));
+ printf(" --> %s", addr_buf);
+ }
+
+ /* Print the netmask */
+ printf(" prefixlen %d ", addr.prefixlen);
+
+ /* Print the scopeid*/
+ if (addr.sin6->sin6_scope_id) {
+ printf("scopeid 0x%x ", addr.sin6->sin6_scope_id);
+ }
+
+ /* Print the flags */
+ if ((addr.flags & IN6_IFF_ANYCAST) != 0) {
+ printf("anycast ");
+ }
+ if ((addr.flags & IN6_IFF_TENTATIVE) != 0) {
+ printf("tentative ");
+ }
+ if ((addr.flags & IN6_IFF_DUPLICATED) != 0) {
+ printf("duplicated ");
+ }
+ if ((addr.flags & IN6_IFF_DETACHED) != 0) {
+ printf("detached ");
+ }
+ if ((addr.flags & IN6_IFF_DEPRECATED) != 0) {
+ printf("deprecated ");
+ }
+ if ((addr.flags & IN6_IFF_AUTOCONF) != 0) {
+ printf("autoconf ");
+ }
+ if ((addr.flags & IN6_IFF_TEMPORARY) != 0) {
+ printf("temporary ");
+ }
+ if ((addr.flags & IN6_IFF_PREFER_SOURCE) != 0) {
+ printf("prefer_source ");
+ }
+
+ /* Print the lifetimes */
+ clock_gettime(CLOCK_MONOTONIC_FAST, &now);
+ if (addr.lifetime.ia6t_preferred || addr.lifetime.ia6t_expire) {
+ printf("pltime ");
+ if (addr.lifetime.ia6t_preferred) {
+ printf("%ld ", MAX(0l,
+ addr.lifetime.ia6t_preferred - now.tv_sec));
+ } else {
+ printf("infty ");
+ }
+
+ printf("vltime ");
+ if (addr.lifetime.ia6t_expire) {
+ printf("%ld ", MAX(0l,
+ addr.lifetime.ia6t_expire - now.tv_sec));
+ } else {
+ printf("infty ");
+ }
+ }
+
+ /* Print the vhid */
+ if (addr.vhid != 0) {
+ printf("vhid %d ", addr.vhid);
+ }
+ printf("\n");
+}
+
+static void
+print_link_addr(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
+{
+ char addr_buf[NI_MAXHOST];
+ struct sockaddr_dl *sdl;
+ int n;
+
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ if ((sdl != NULL) && (sdl->sdl_alen > 0)) {
+ if (((sdl->sdl_type == IFT_ETHER) ||
+ (sdl->sdl_type == IFT_L2VLAN) ||
+ (sdl->sdl_type == IFT_BRIDGE)) &&
+ (sdl->sdl_alen == ETHER_ADDR_LEN)) {
+ ether_ntoa_r((struct ether_addr *)LLADDR(sdl),
+ addr_buf);
+ printf("\tether %s\n", addr_buf);
+ } else {
+ n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
+
+ printf("\tlladdr %s\n", link_ntoa(sdl) + n);
+ }
+ }
+}
+
+static void
+print_ifaddr(ifconfig_handle_t *lifh, struct ifaddrs *ifa, void *udata __unused)
+{
+ switch (ifa->ifa_addr->sa_family) {
+ case AF_INET:
+ print_inet4_addr(lifh, ifa);
+ break;
+ case AF_INET6:
+
+ /*
+ * printing AF_INET6 status requires calling SIOCGIFAFLAG_IN6
+ * and SIOCGIFALIFETIME_IN6. TODO: figure out the best way to
+ * do that from within libifconfig
+ */
+ print_inet6_addr(lifh, ifa);
+ break;
+ case AF_LINK:
+ print_link_addr(lifh, ifa);
+ break;
+ case AF_LOCAL:
+ case AF_UNSPEC:
+ default:
+ /* TODO */
+ break;
+ }
+}
+
+static void
+print_nd6(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
+{
+ struct in6_ndireq nd;
+
+ if (ifconfig_get_nd6(lifh, ifa->ifa_name, &nd) == 0) {
+ printf("\tnd6 options=%x\n", nd.ndi.flags);
+ } else {
+ err(1, "Failed to get nd6 options");
+ }
+}
+
+static void
+print_fib(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
+{
+ int fib;
+
+ if (ifconfig_get_fib(lifh, ifa->ifa_name, &fib) == 0) {
+ printf("\tfib: %d\n", fib);
+ } else {
+ err(1, "Failed to get interface FIB");
+ }
+}
+
+static void
+print_lagg(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
+{
+ struct lagg_protos lpr[] = LAGG_PROTOS;
+ struct ifconfig_lagg_status *ls;
+ struct lacp_opreq *lp;
+ const char *proto = "<unknown>";
+ int i;
+
+ if (ifconfig_lagg_get_lagg_status(lifh, ifa->ifa_name, &ls) < 0) {
+ if (ifconfig_err_errno(lifh) == EINVAL) {
+ return;
+ }
+ err(1, "Failed to get interface lagg status");
+ }
+
+ /* First print the proto */
+ for (i = 0; i < nitems(lpr); i++) {
+ if (ls->ra->ra_proto == lpr[i].lpr_proto) {
+ proto = lpr[i].lpr_name;
+ break;
+ }
+ }
+ printf("\tlaggproto %s", proto);
+
+ /* Now print the lagg hash */
+ if (ls->rf->rf_flags & LAGG_F_HASHMASK) {
+ const char *sep = "";
+
+ printf(" lagghash ");
+ if (ls->rf->rf_flags & LAGG_F_HASHL2) {
+ printf("%sl2", sep);
+ sep = ",";
+ }
+ if (ls->rf->rf_flags & LAGG_F_HASHL3) {
+ printf("%sl3", sep);
+ sep = ",";
+ }
+ if (ls->rf->rf_flags & LAGG_F_HASHL4) {
+ printf("%sl4", sep);
+ sep = ",";
+ }
+ }
+ putchar('\n');
+ printf("\tlagg options:\n");
+ printf("\t\tflags=%x", ls->ro->ro_opts);
+ putchar('\n');
+ printf("\t\tflowid_shift: %d\n", ls->ro->ro_flowid_shift);
+ if (ls->ra->ra_proto == LAGG_PROTO_ROUNDROBIN) {
+ printf("\t\trr_limit: %d\n", ls->ro->ro_bkt);
+ }
+ printf("\tlagg statistics:\n");
+ printf("\t\tactive ports: %d\n", ls->ro->ro_active);
+ printf("\t\tflapping: %u\n", ls->ro->ro_flapping);
+ for (i = 0; i < ls->ra->ra_ports; i++) {
+ lp = (struct lacp_opreq *)&ls->ra->ra_port[i].rp_lacpreq;
+ printf("\tlaggport: %s ", ls->ra->ra_port[i].rp_portname);
+ printf("flags=%x", ls->ra->ra_port[i].rp_flags);
+ if (ls->ra->ra_proto == LAGG_PROTO_LACP) {
+ printf(" state=%x", lp->actor_state);
+ }
+ putchar('\n');
+ }
+
+ printf("\n");
+ ifconfig_lagg_free_lagg_status(ls);
+}
+
+static void
+print_laggport(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
+{
+ struct lagg_reqport rp;
+
+ if (ifconfig_lagg_get_laggport_status(lifh, ifa->ifa_name, &rp) < 0) {
+ if ((ifconfig_err_errno(lifh) == EINVAL) ||
+ (ifconfig_err_errno(lifh) == ENOENT)) {
+ return;
+ } else {
+ err(1, "Failed to get lagg port status");
+ }
+ }
+
+ printf("\tlaggdev: %s\n", rp.rp_ifname);
+}
+
+static void
+print_groups(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
+{
+ struct ifgroupreq ifgr;
+ struct ifg_req *ifg;
+ int len;
+ int cnt = 0;
+
+ if (ifconfig_get_groups(lifh, ifa->ifa_name, &ifgr) != 0) {
+ err(1, "Failed to get groups");
+ }
+
+ ifg = ifgr.ifgr_groups;
+ len = ifgr.ifgr_len;
+ for (; ifg && len >= sizeof(struct ifg_req); ifg++) {
+ len -= sizeof(struct ifg_req);
+ if (strcmp(ifg->ifgrq_group, "all")) {
+ if (cnt == 0) {
+ printf("\tgroups: ");
+ }
+ cnt++;
+ printf("%s ", ifg->ifgrq_group);
+ }
+ }
+ if (cnt) {
+ printf("\n");
+ }
+
+ free(ifgr.ifgr_groups);
+}
+
+static void
+print_media(ifconfig_handle_t *lifh, struct ifaddrs *ifa)
+{
+ int i;
+
+ /* Outline:
+ * 1) Determine whether the iface supports SIOGIFMEDIA or SIOGIFXMEDIA
+ * 2) Get the full media list
+ * 3) Print the current media word
+ * 4) Print the active media word, if different
+ * 5) Print the status
+ * 6) Print the supported media list
+ *
+ * How to print the media word:
+ * 1) Get the top-level interface type and description
+ * 2) Print the subtype
+ * 3) For current word only, print the top type, if it exists
+ * 4) Print options list
+ * 5) Print the instance, if there is one
+ *
+ * How to get the top-level interface type
+ * 1) Shift ifmw right by 0x20 and index into IFM_TYPE_DESCRIPTIONS
+ *
+ * How to get the top-level interface subtype
+ * 1) Shift ifmw right by 0x20, index into ifmedia_types_to_subtypes
+ * 2) Iterate through the resulting table's subtypes table, ignoring
+ * aliases. Iterate through the resulting ifmedia_description
+ * tables, finding an entry with the right media subtype
+ */
+ struct ifmediareq *ifmr;
+
+ if (ifconfig_media_get_mediareq(lifh, ifa->ifa_name, &ifmr) != 0) {
+ if (ifconfig_err_errtype(lifh) != OK) {
+ err(1, "Failed to get media info");
+ } else {
+ return; /* Interface doesn't support media info */
+ }
+ }
+
+ printf("\tmedia: %s %s", ifconfig_media_get_type(ifmr->ifm_current),
+ ifconfig_media_get_subtype(ifmr->ifm_current));
+ if (ifmr->ifm_active != ifmr->ifm_current) {
+ const char **options;
+
+ printf(" (%s", ifconfig_media_get_subtype(ifmr->ifm_active));
+ options = ifconfig_media_get_options(ifmr->ifm_active);
+ if (options != NULL && options[0] != NULL) {
+ printf(" <%s", options[0]);
+ for (size_t i = 1; options[i] != NULL; ++i)
+ printf(",%s", options[i]);
+ printf(">)\n");
+ } else {
+ printf(")\n");
+ }
+ free(options);
+ } else {
+ printf("\n");
+ }
+
+ if (ifmr->ifm_status & IFM_AVALID) {
+ printf("\tstatus: %s\n",
+ ifconfig_media_get_status(ifmr));
+ }
+
+ printf("\tsupported media:\n");
+ for (i = 0; i < ifmr->ifm_count; i++) {
+ const char **options;
+
+ printf("\t\tmedia %s",
+ ifconfig_media_get_subtype(ifmr->ifm_ulist[i]));
+ options = ifconfig_media_get_options(ifmr->ifm_ulist[i]);
+ if (options != NULL && options[0] != NULL) {
+ printf(" mediaopt %s", options[0]);
+ for (size_t i = 1; options[i] != NULL; ++i)
+ printf(",%s", options[i]);
+ printf("\n");
+ } else {
+ printf("\n");
+ }
+ free(options);
+ }
+ free(ifmr);
+}
+
+static void
+print_iface(ifconfig_handle_t *lifh, struct ifaddrs *ifa, void *udata __unused)
+{
+ int metric, mtu;
+ char *description = NULL;
+ struct ifconfig_capabilities caps;
+ struct ifstat ifs;
+
+ printf("%s: flags=%x ", ifa->ifa_name, ifa->ifa_flags);
+
+ if (ifconfig_get_metric(lifh, ifa->ifa_name, &metric) == 0) {
+ printf("metric %d ", metric);
+ } else {
+ err(1, "Failed to get interface metric");
+ }
+
+ if (ifconfig_get_mtu(lifh, ifa->ifa_name, &mtu) == 0) {
+ printf("mtu %d\n", mtu);
+ } else {
+ err(1, "Failed to get interface MTU");
+ }
+
+ if (ifconfig_get_description(lifh, ifa->ifa_name, &description) == 0) {
+ printf("\tdescription: %s\n", description);
+ }
+
+ if (ifconfig_get_capability(lifh, ifa->ifa_name, &caps) == 0) {
+ if (caps.curcap != 0) {
+ printf("\toptions=%x\n", caps.curcap);
+ }
+ if (caps.reqcap != 0) {
+ printf("\tcapabilities=%x\n", caps.reqcap);
+ }
+ } else {
+ err(1, "Failed to get interface capabilities");
+ }
+
+ ifconfig_foreach_ifaddr(lifh, ifa, print_ifaddr, NULL);
+
+ /* This paragraph is equivalent to ifconfig's af_other_status funcs */
+ print_nd6(lifh, ifa);
+ print_media(lifh, ifa);
+ print_groups(lifh, ifa);
+ print_fib(lifh, ifa);
+ print_carp(lifh, ifa);
+ print_lagg(lifh, ifa);
+ print_laggport(lifh, ifa);
+
+ if (ifconfig_get_ifstatus(lifh, ifa->ifa_name, &ifs) == 0) {
+ printf("%s", ifs.ascii);
+ }
+
+ free(description);
+}
+
+int
+main(int argc, char *argv[])
+{
+ ifconfig_handle_t *lifh;
+
+ if (argc != 1) {
+ errx(1, "Usage: example_status");
+ }
+
+ lifh = ifconfig_open();
+ if (lifh == NULL) {
+ errx(1, "Failed to open libifconfig handle.");
+ }
+
+ if (ifconfig_foreach_iface(lifh, print_iface, NULL) != 0) {
+ err(1, "Failed to get interfaces");
+ }
+
+ ifconfig_close(lifh);
+ lifh = NULL;
+ return (-1);
+}
diff --git a/share/examples/libusb20/Makefile b/share/examples/libusb20/Makefile
new file mode 100644
index 000000000000..262f1ac3825a
--- /dev/null
+++ b/share/examples/libusb20/Makefile
@@ -0,0 +1,16 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/libusb20
+TARGETS= bulk control
+CFLAGS+= -Wall
+
+all: $(TARGETS)
+
+bulk: bulk.o util.o
+ $(CC) $(CFLAGS) -o bulk bulk.o util.o -lusb
+
+control: control.o util.o
+ $(CC) $(CFLAGS) -o control control.o util.o -lusb
+
+clean:
+ rm -f $(TARGETS) *.o *~
diff --git a/share/examples/libusb20/README b/share/examples/libusb20/README
new file mode 100644
index 000000000000..a2c1510aae2b
--- /dev/null
+++ b/share/examples/libusb20/README
@@ -0,0 +1,40 @@
+As I dug my own way through the documentation of libusb 2.0 that ships
+with FreeBSD 8+ as the OS'es own USB library API, I noticed there are
+only few code examples around under /usr/src (namely, usbconfig
+itself).
+
+The libusb20(3) man page is a starting point, but it's a reference
+manual, nothing less, nothing more. Using just a reference, it's not
+very easy to start writing your own code based on that.
+
+So I started writing my own examples, to "get a feeling" about how to
+use the library. I covered two typical scenarios which are common for
+a number of devices.
+
+The first one is called "bulk", and uses bulk output (host to device)
+and input transfers to talk to an USB device.
+
+The second one is called "control", and can use both control output
+and input transfers, as well as so-called interrupt transfers. The
+latter are used for data that are being reported frequently or
+repeatedly, like position updates from a pointing device (mouse).
+Despite of its name, the host has to poll devices for their interrupt
+transfers on each USB frame (i.e., each 1 ms).
+
+Recommended reading is the USB 3.0 specification (the older 2.0 one
+would do as well), to be found under
+
+http://www.usb.org/developers/docs/
+
+as well as documents for individual USB device classes where
+appropriate.
+
+Feel free to be liberal in the licensing of these examples: while the
+beer-ware license mandates to keep the license notice, this only
+applies to modifications of the original examples itself. For
+copy&pasting (even a larger) piece of an example into your own work, I
+won't imply you have to reproduce the beer-ware license text there.
+Feel free to credit my name in your derived work if you want.
+
+Dresden, July 2012
+Joerg Wunsch <joerg@FreeBSD.org>
diff --git a/share/examples/libusb20/bulk.c b/share/examples/libusb20/bulk.c
new file mode 100644
index 000000000000..2f7588bd592f
--- /dev/null
+++ b/share/examples/libusb20/bulk.c
@@ -0,0 +1,244 @@
+/*-
+ * SPDX-License-Identifier: Beerware
+ *
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp):
+ * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch
+ * ----------------------------------------------------------------------------
+ */
+
+/*
+ * Simple demo program to illustrate the handling of FreeBSD's
+ * libusb20.
+ *
+ * Issues a bulk output, and then requests a bulk input.
+ */
+
+/*
+ * Examples:
+ * Just list all VID:PID pairs
+ * ./bulk
+ *
+ * Say "hello" to an Atmel JTAGICEmkII.
+ * ./bulk -o 2 -i 0x82 -v 0x03eb -p 0x2103 0x1b 0 0 1 0 0 0 0x0e 1 0xf3 0x97
+ *
+ * Return the INQUIRY data of an USB mass storage device.
+ * (It's best to have the umass(4) driver unloaded while doing such
+ * experiments, and perform a "usbconfig reset" for the device if it
+ * gets stuck.)
+ * ./bulk -v 0x5e3 -p 0x723 -i 0x81 -o 2 0x55 0x53 0x42 0x43 1 2 3 4 31 12 0x80 0x24 0 0 0 0x12 0 0 0 36 0 0 0 0 0 0 0 0 0 0
+ */
+
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include <libusb20.h>
+#include <libusb20_desc.h>
+
+#include "util.h"
+
+/*
+ * If you want to see the details of the internal datastructures
+ * in the debugger, unifdef the following.
+ */
+#ifdef DEBUG
+# include <sys/queue.h>
+# include "/usr/src/lib/libusb/libusb20_int.h"
+#endif
+
+#define BUFLEN 64
+
+#define TIMEOUT 5000 /* 5 s */
+
+int in_ep, out_ep; /* endpoints */
+uint8_t out_buf[BUFLEN];
+uint16_t out_len;
+
+static void
+doit(struct libusb20_device *dev)
+{
+ int rv;
+
+ /*
+ * Open the device, allocating memory for two possible (bulk or
+ * interrupt) transfers.
+ *
+ * If only control transfers are intended (via
+ * libusb20_dev_request_sync()), transfer_max can be given as 0.
+ */
+ if ((rv = libusb20_dev_open(dev, 2)) != 0)
+ {
+ fprintf(stderr, "libusb20_dev_open: %s\n", libusb20_strerror(rv));
+ return;
+ }
+
+ /*
+ * If the device has more than one configuration, select the desired
+ * one here.
+ */
+ if ((rv = libusb20_dev_set_config_index(dev, 0)) != 0)
+ {
+ fprintf(stderr, "libusb20_dev_set_config_index: %s\n", libusb20_strerror(rv));
+ return;
+ }
+
+ /*
+ * Two transfers have been requested in libusb20_dev_open() above;
+ * obtain the corresponding transfer struct pointers.
+ */
+ struct libusb20_transfer *xfr_out = libusb20_tr_get_pointer(dev, 0);
+ struct libusb20_transfer *xfr_in = libusb20_tr_get_pointer(dev, 1);
+
+ if (xfr_in == NULL || xfr_out == NULL)
+ {
+ fprintf(stderr, "libusb20_tr_get_pointer: %s\n", libusb20_strerror(rv));
+ return;
+ }
+
+ /*
+ * Open both transfers, the "out" one for the write endpoint, the
+ * "in" one for the read endpoint (ep | 0x80).
+ */
+ if ((rv = libusb20_tr_open(xfr_out, 0, 1, out_ep)) != 0)
+ {
+ fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv));
+ return;
+ }
+ if ((rv = libusb20_tr_open(xfr_in, 0, 1, in_ep)) != 0)
+ {
+ fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv));
+ return;
+ }
+
+ uint8_t in_buf[BUFLEN];
+ uint32_t rlen;
+
+ if (out_len > 0)
+ {
+ if ((rv = libusb20_tr_bulk_intr_sync(xfr_out, out_buf, out_len, &rlen, TIMEOUT))
+ != 0)
+ {
+ fprintf(stderr, "libusb20_tr_bulk_intr_sync (OUT): %s\n", libusb20_strerror(rv));
+ }
+ printf("sent %d bytes\n", rlen);
+ }
+
+ if ((rv = libusb20_tr_bulk_intr_sync(xfr_in, in_buf, BUFLEN, &rlen, TIMEOUT))
+ != 0)
+ {
+ fprintf(stderr, "libusb20_tr_bulk_intr_sync: %s\n", libusb20_strerror(rv));
+ }
+ printf("received %d bytes\n", rlen);
+ if (rlen > 0)
+ print_formatted(in_buf, rlen);
+
+ libusb20_tr_close(xfr_out);
+ libusb20_tr_close(xfr_in);
+
+ libusb20_dev_close(dev);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "Usage ./usb -i <IN_EP> -o <OUT_EP> -v <VID> -p <PID> [<outdata> ...\n]");
+ exit(EX_USAGE);
+}
+
+int
+main(int argc, char **argv)
+{
+ unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */
+ int c;
+
+ while ((c = getopt(argc, argv, "i:o:p:v:")) != -1)
+ switch (c)
+ {
+ case 'i':
+ in_ep = strtol(optarg, NULL, 0);
+ break;
+
+ case 'o':
+ out_ep = strtol(optarg, NULL, 0);
+ break;
+
+ case 'p':
+ pid = strtol(optarg, NULL, 0);
+ break;
+
+ case 'v':
+ vid = strtol(optarg, NULL, 0);
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (vid != UINT_MAX || pid != UINT_MAX)
+ {
+ if (in_ep == 0 || out_ep == 0)
+ {
+ usage();
+ }
+ if ((in_ep & 0x80) == 0)
+ {
+ fprintf(stderr, "IN_EP must have bit 7 set\n");
+ return (EX_USAGE);
+ }
+
+ if (argc > 0)
+ {
+ for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--)
+ {
+ unsigned n = strtoul(argv[out_len], 0, 0);
+ if (n > 255)
+ fprintf(stderr,
+ "Warning: data #%d 0x%0x > 0xff, truncating\n",
+ out_len, n);
+ out_buf[out_len] = (uint8_t)n;
+ }
+ out_len++;
+ if (argc > 0)
+ fprintf(stderr,
+ "Data count exceeds maximum of %d, ignoring %d elements\n",
+ BUFLEN, optind);
+ }
+ }
+
+ struct libusb20_backend *be;
+ struct libusb20_device *dev;
+
+ if ((be = libusb20_be_alloc_default()) == NULL)
+ {
+ perror("libusb20_be_alloc()");
+ return 1;
+ }
+
+ dev = NULL;
+ while ((dev = libusb20_be_device_foreach(be, dev)) != NULL)
+ {
+ struct LIBUSB20_DEVICE_DESC_DECODED *ddp =
+ libusb20_dev_get_device_desc(dev);
+
+ printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n",
+ libusb20_dev_get_desc(dev),
+ ddp->idVendor, ddp->idProduct);
+
+ if (ddp->idVendor == vid && ddp->idProduct == pid)
+ doit(dev);
+ }
+
+ libusb20_be_free(be);
+ return 0;
+}
diff --git a/share/examples/libusb20/control.c b/share/examples/libusb20/control.c
new file mode 100644
index 000000000000..e2ae8f74cc32
--- /dev/null
+++ b/share/examples/libusb20/control.c
@@ -0,0 +1,416 @@
+/*-
+ * SPDX-License-Identifier: Beerware
+ *
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp):
+ * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch
+ * ----------------------------------------------------------------------------
+ */
+
+/*
+ * Simple demo program to illustrate the handling of FreeBSD's
+ * libusb20.
+ */
+
+/*
+ * Examples:
+ * Just list all VID:PID pairs
+ * ./control
+ *
+ * Standard device request GET_STATUS, report two bytes of status
+ * (bit 0 in the first byte returned is the "self powered" bit)
+ * ./control -v 0x3eb -p 0x2103 in std dev get_status 0 0 2
+ *
+ * Request input reports through the interrupt pipe from a mouse
+ * device (move the mouse around after issuing the command):
+ * ./control -v 0x093a -p 0x2516 -i 0x81
+ *
+ */
+
+
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <libusb20.h>
+#include <libusb20_desc.h>
+
+#include <sys/queue.h>
+
+#include "util.h"
+
+/*
+ * If you want to see the details of the internal datastructures
+ * in the debugger, unifdef the following.
+ */
+#ifdef DEBUG
+# include "/usr/src/lib/libusb/libusb20_int.h"
+#endif
+
+#define BUFLEN 64
+
+#define TIMEOUT 5000 /* 5 s */
+
+int intr_ep; /* endpoints */
+struct LIBUSB20_CONTROL_SETUP_DECODED setup;
+
+uint8_t out_buf[BUFLEN];
+uint16_t out_len;
+
+bool do_request;
+
+static void
+doit(struct libusb20_device *dev)
+{
+ int rv;
+
+ if (do_request)
+ printf("doit(): bmRequestType 0x%02x, bRequest 0x%02x, wValue 0x%04x, wIndex 0x%04x, wLength 0x%04x\n",
+ setup.bmRequestType,
+ setup.bRequest,
+ setup.wValue,
+ setup.wIndex,
+ setup.wLength);
+
+ /*
+ * Open the device, allocating memory for two possible (bulk or
+ * interrupt) transfers.
+ *
+ * If only control transfers are intended (via
+ * libusb20_dev_request_sync()), transfer_max can be given as 0.
+ */
+ if ((rv = libusb20_dev_open(dev, 1)) != 0)
+ {
+ fprintf(stderr, "libusb20_dev_open: %s\n", libusb20_strerror(rv));
+ return;
+ }
+
+ /*
+ * If the device has more than one configuration, select the desired
+ * one here.
+ */
+ if ((rv = libusb20_dev_set_config_index(dev, 0)) != 0)
+ {
+ fprintf(stderr, "libusb20_dev_set_config_index: %s\n", libusb20_strerror(rv));
+ return;
+ }
+
+ uint8_t *data = 0;
+ uint16_t actlen;
+
+ if ((setup.bmRequestType & 0x80) != 0)
+ {
+ /* this is an IN request, allocate a buffer */
+ data = malloc(setup.wLength);
+ if (data == 0)
+ {
+ fprintf(stderr,
+ "Out of memory allocating %u bytes of reply buffer\n",
+ setup.wLength);
+ return;
+ }
+ }
+ else
+ data = out_buf;
+
+ if (do_request)
+ {
+ if ((rv = libusb20_dev_request_sync(dev, &setup, data,
+ &actlen,
+ TIMEOUT,
+ 0 /* flags */)) != 0)
+ {
+ fprintf(stderr,
+ "libusb20_dev_request_sync: %s\n", libusb20_strerror(rv));
+ }
+ printf("sent %d bytes\n", actlen);
+ if ((setup.bmRequestType & 0x80) != 0)
+ {
+ print_formatted(data, (uint32_t)setup.wLength);
+ free(data);
+ }
+ }
+
+ if (intr_ep != 0)
+ {
+ /*
+ * One transfer has been requested in libusb20_dev_open() above;
+ * obtain the corresponding transfer struct pointer.
+ */
+ struct libusb20_transfer *xfr_intr = libusb20_tr_get_pointer(dev, 0);
+
+ if (xfr_intr == NULL)
+ {
+ fprintf(stderr, "libusb20_tr_get_pointer: %s\n", libusb20_strerror(rv));
+ return;
+ }
+
+ /*
+ * Open the interrupt transfer.
+ */
+ if ((rv = libusb20_tr_open(xfr_intr, 0, 1, intr_ep)) != 0)
+ {
+ fprintf(stderr, "libusb20_tr_open: %s\n", libusb20_strerror(rv));
+ return;
+ }
+
+ uint8_t in_buf[BUFLEN];
+ uint32_t rlen;
+
+ if ((rv = libusb20_tr_bulk_intr_sync(xfr_intr, in_buf, BUFLEN, &rlen, TIMEOUT))
+ != 0)
+ {
+ fprintf(stderr, "libusb20_tr_bulk_intr_sync: %s\n", libusb20_strerror(rv));
+ }
+ printf("received %d bytes\n", rlen);
+ if (rlen > 0)
+ print_formatted(in_buf, rlen);
+
+ libusb20_tr_close(xfr_intr);
+ }
+
+ libusb20_dev_close(dev);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "Usage ./usb [-i <INTR_EP>] -v <VID> -p <PID> [dir type rcpt req wValue wIndex wLength [<outdata> ...]]\n");
+ exit(EX_USAGE);
+}
+
+static const char *reqnames[] =
+{
+ "get_status",
+ "clear_feature",
+ "res1",
+ "set_feature",
+ "res2",
+ "set_address",
+ "get_descriptor",
+ "set_descriptor",
+ "get_configuration",
+ "set_configuration",
+ "get_interface",
+ "set_interface",
+ "synch_frame",
+};
+
+static int
+get_req(const char *reqname)
+{
+ size_t i;
+ size_t l = strlen(reqname);
+
+ for (i = 0;
+ i < sizeof reqnames / sizeof reqnames[0];
+ i++)
+ if (strncasecmp(reqname, reqnames[i], l) == 0)
+ return i;
+
+ return strtoul(reqname, 0, 0);
+}
+
+
+static int
+parse_req(int argc, char **argv)
+{
+ int idx;
+ uint8_t rt = 0;
+
+ for (idx = 0; argc != 0 && idx <= 6; argc--, idx++)
+ switch (idx)
+ {
+ case 0:
+ /* dir[ection]: i[n] | o[ut] */
+ if (*argv[idx] == 'i')
+ rt |= 0x80;
+ else if (*argv[idx] == 'o')
+ /* nop */;
+ else
+ {
+ fprintf(stderr, "request direction must be \"in\" or \"out\" (got %s)\n",
+ argv[idx]);
+ return -1;
+ }
+ break;
+
+ case 1:
+ /* type: s[tandard] | c[lass] | v[endor] */
+ if (*argv[idx] == 's')
+ /* nop */;
+ else if (*argv[idx] == 'c')
+ rt |= 0x20;
+ else if (*argv[idx] == 'v')
+ rt |= 0x40;
+ else
+ {
+ fprintf(stderr,
+ "request type must be one of \"standard\", \"class\", or \"vendor\" (got %s)\n",
+ argv[idx]);
+ return -1;
+ }
+ break;
+
+ case 2:
+ /* rcpt: d[evice], i[nterface], e[ndpoint], o[ther] */
+ if (*argv[idx] == 'd')
+ /* nop */;
+ else if (*argv[idx] == 'i')
+ rt |= 1;
+ else if (*argv[idx] == 'e')
+ rt |= 2;
+ else if (*argv[idx] == 'o')
+ rt |= 3;
+ else
+ {
+ fprintf(stderr,
+ "recipient must be one of \"device\", \"interface\", \"endpoint\", or \"other\" (got %s)\n",
+ argv[idx]);
+ return -1;
+ }
+ setup.bmRequestType = rt;
+ break;
+
+ case 3:
+ setup.bRequest = get_req(argv[idx]);
+ break;
+
+ case 4:
+ setup.wValue = strtoul(argv[idx], 0, 0);
+ break;
+
+ case 5:
+ setup.wIndex = strtoul(argv[idx], 0, 0);
+ break;
+
+ case 6:
+ setup.wLength = strtoul(argv[idx], 0, 0);
+ break;
+ }
+
+ return argc;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ unsigned int vid = UINT_MAX, pid = UINT_MAX; /* impossible VID:PID */
+ int c;
+
+ /*
+ * Initialize setup struct. This step is required, and initializes
+ * internal fields in the struct.
+ *
+ * All the "public" fields are named exactly the way as the USB
+ * standard describes them, namely:
+ *
+ * setup.bmRequestType: bitmask, bit 7 is direction
+ * bits 6/5 is request type
+ * (standard, class, vendor)
+ * bits 4..0 is recipient
+ * (device, interface, endpoint,
+ * other)
+ * setup.bRequest: the request itself (see get_req() for standard
+ * requests, or specific value)
+ * setup.wValue: a 16-bit value
+ * setup.wIndex: another 16-bit value
+ * setup.wLength: length of associated data transfer, direction
+ * depends on bit 7 of bmRequestType
+ */
+ LIBUSB20_INIT(LIBUSB20_CONTROL_SETUP, &setup);
+
+ while ((c = getopt(argc, argv, "i:p:v:")) != -1)
+ switch (c)
+ {
+ case 'i':
+ intr_ep = strtol(optarg, NULL, 0);
+ break;
+
+ case 'p':
+ pid = strtol(optarg, NULL, 0);
+ break;
+
+ case 'v':
+ vid = strtol(optarg, NULL, 0);
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (vid != UINT_MAX || pid != UINT_MAX)
+ {
+ if (intr_ep != 0 && (intr_ep & 0x80) == 0)
+ {
+ fprintf(stderr, "Interrupt endpoint must be of type IN\n");
+ usage();
+ }
+
+ if (argc > 0)
+ {
+ do_request = true;
+
+ int rv = parse_req(argc, argv);
+ if (rv < 0)
+ return EX_USAGE;
+ argc = rv;
+
+ if (argc > 0)
+ {
+ for (out_len = 0; argc > 0 && out_len < BUFLEN; out_len++, argc--)
+ {
+ unsigned n = strtoul(argv[out_len], 0, 0);
+ if (n > 255)
+ fprintf(stderr,
+ "Warning: data #%d 0x%0x > 0xff, truncating\n",
+ out_len, n);
+ out_buf[out_len] = (uint8_t)n;
+ }
+ out_len++;
+ if (argc > 0)
+ fprintf(stderr,
+ "Data count exceeds maximum of %d, ignoring %d elements\n",
+ BUFLEN, optind);
+ }
+ }
+ }
+
+ struct libusb20_backend *be;
+ struct libusb20_device *dev;
+
+ if ((be = libusb20_be_alloc_default()) == NULL)
+ {
+ perror("libusb20_be_alloc()");
+ return 1;
+ }
+
+ dev = NULL;
+ while ((dev = libusb20_be_device_foreach(be, dev)) != NULL)
+ {
+ struct LIBUSB20_DEVICE_DESC_DECODED *ddp =
+ libusb20_dev_get_device_desc(dev);
+
+ printf("Found device %s (VID:PID = 0x%04x:0x%04x)\n",
+ libusb20_dev_get_desc(dev),
+ ddp->idVendor, ddp->idProduct);
+
+ if (ddp->idVendor == vid && ddp->idProduct == pid)
+ doit(dev);
+ }
+
+ libusb20_be_free(be);
+ return 0;
+}
diff --git a/share/examples/libusb20/util.c b/share/examples/libusb20/util.c
new file mode 100644
index 000000000000..e57e439d8199
--- /dev/null
+++ b/share/examples/libusb20/util.c
@@ -0,0 +1,48 @@
+/* ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp):
+ * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch
+ * ----------------------------------------------------------------------------
+ */
+
+/*
+ * Helper functions common to all examples
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <libusb20.h>
+#include <libusb20_desc.h>
+
+#include "util.h"
+
+/*
+ * Print "len" bytes from "buf" in hex, followed by an ASCII
+ * representation (somewhat resembling the output of hd(1)).
+ */
+void
+print_formatted(uint8_t *buf, uint32_t len)
+{
+ int i, j;
+
+ for (j = 0; j < len; j += 16)
+ {
+ printf("%02x: ", j);
+
+ for (i = 0; i < 16 && i + j < len; i++)
+ printf("%02x ", buf[i + j]);
+ printf(" ");
+ for (i = 0; i < 16 && i + j < len; i++)
+ {
+ uint8_t c = buf[i + j];
+ if(c >= ' ' && c <= '~')
+ printf("%c", (char)c);
+ else
+ putchar('.');
+ }
+ putchar('\n');
+ }
+}
diff --git a/share/examples/libusb20/util.h b/share/examples/libusb20/util.h
new file mode 100644
index 000000000000..a54ba709b9e9
--- /dev/null
+++ b/share/examples/libusb20/util.h
@@ -0,0 +1,12 @@
+/* ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42) (by Poul-Henning Kamp):
+ * <joerg@FreeBSD.ORG> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Joerg Wunsch
+ * ----------------------------------------------------------------------------
+ */
+
+#include <stdint.h>
+#include <libusb20.h>
+
+void print_formatted(uint8_t *buf, uint32_t len);
diff --git a/share/examples/libvgl/Makefile b/share/examples/libvgl/Makefile
new file mode 100644
index 000000000000..ebfa7eaa47ea
--- /dev/null
+++ b/share/examples/libvgl/Makefile
@@ -0,0 +1,9 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/libvgl
+PROG= demo
+MAN=
+DPADD= ${LIBVGL}
+LDADD= -lvgl
+
+.include <bsd.prog.mk>
diff --git a/share/examples/libvgl/Makefile.depend b/share/examples/libvgl/Makefile.depend
new file mode 100644
index 000000000000..5f049ceb808c
--- /dev/null
+++ b/share/examples/libvgl/Makefile.depend
@@ -0,0 +1,17 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libvgl \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/share/examples/libvgl/demo.c b/share/examples/libvgl/demo.c
new file mode 100644
index 000000000000..615a62815cea
--- /dev/null
+++ b/share/examples/libvgl/demo.c
@@ -0,0 +1,122 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1991-1997 Søren Schmidt
+ * 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
+ * in this position and unchanged.
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/fbio.h>
+#include <sys/kbio.h>
+#include <sys/consio.h>
+#include <vgl.h>
+
+int
+main(int argc, char **argv)
+{
+ int y, xsize, ysize, i,j;
+ VGLBitmap *tmp;
+
+ // set graphics mode, here 320x240 256 colors
+ // supported modes are (from <sys/consio.h>):
+ // SW_VGA_CG320: std VGA 320x200 256 colors
+ // SW_VGA_MODEX: Modex VGA 320x240 256 colors
+ // SW_VGA_VG640: std VGA 640x480 16 colors
+ VGLInit(SW_VGA_MODEX);
+
+ // initialize mouse and show pointer
+ VGLMouseInit(VGL_MOUSESHOW);
+
+ // VGLDisplay is a ptr to a struct Bitmap defined and initialized by
+ // libvgl. The Bitmap points directly to screen memory etc.
+ xsize=VGLDisplay->Xsize;
+ ysize=VGLDisplay->Ysize;
+
+ // alloc a new bitmap
+ tmp = VGLBitmapCreate(MEMBUF, 256, 256, NULL);
+ VGLBitmapAllocateBits(tmp);
+ VGLClear(tmp, 0);
+
+ // fill the screen with colored lines
+ for (y=0; y<ysize; y++)
+ VGLLine(VGLDisplay, 0, y, xsize-1, y, y/2 % 256);
+
+ // draw some lines and circles just to show off
+ VGLLine(VGLDisplay, 0, 0, xsize-1, ysize-1, 63);
+ VGLLine(VGLDisplay, 0, ysize-1, xsize-1, 0, 63);
+ VGLLine(VGLDisplay, 0, 0, 0, ysize-1, 63);
+ VGLLine(VGLDisplay, xsize-1, 0, xsize-1, ysize-1, 63);
+ VGLEllipse(VGLDisplay, 256, 0, 256, 256, 63);
+ VGLEllipse(VGLDisplay, 0, 256, 256, 256, 0);
+
+ // some text is also useful
+ VGLBitmapString(VGLDisplay, 100,100,
+ "This is text", 63, 0, 0, VGL_DIR_RIGHT);
+ sleep(2);
+ VGLBitmapString(VGLDisplay, 100,100,
+ "This is text", 63, 0, 0, VGL_DIR_UP);
+ sleep(2);
+ VGLBitmapString(VGLDisplay, 100,100,
+ "This is text", 63, 0, 0, VGL_DIR_LEFT);
+ sleep(2);
+ VGLBitmapString(VGLDisplay, 100,100,
+ "This is text", 63, 0, 0, VGL_DIR_DOWN);
+ sleep(2);
+
+ // now show some simple bitblit
+ for (i=0; i<256; i++)
+ for (j=0; j<256; j++)
+ tmp->Bitmap[i+256*j] = i%16;
+ VGLBitmapCopy(tmp, 0, 0, VGLDisplay, 0, 0, 128, 128);
+ for (i=0; i<256; i++)
+ for (j=0; j<256; j++)
+ tmp->Bitmap[i+256*j] = j%16;
+ VGLBitmapCopy(tmp, 0, 0, VGLDisplay, 3, 128, 128, 128);
+ sleep(2);
+ VGLBitmapCopy(VGLDisplay, 237, 311, tmp, 64, 64, 128, 128);
+ VGLBitmapCopy(tmp, 32, 32, VGLDisplay, 400, 128, 128, 128);
+ sleep(2);
+ VGLBitmapCopy(VGLDisplay, 300, 300, VGLDisplay, 500, 128, 128, 128);
+ sleep(5);
+ i=0;
+
+ // loop around drawing and copying
+ while (++i) {
+ VGLBitmapCopy(VGLDisplay, rand()%xsize, rand()%ysize,
+ VGLDisplay, rand()%xsize, rand()%ysize,
+ rand()%xsize, rand()%ysize);
+ VGLLine(VGLDisplay, rand()%xsize, rand()%ysize,
+ rand()%xsize, rand()%ysize, rand()%256);
+ VGLEllipse(VGLDisplay, rand()%xsize, rand()%ysize,
+ rand()%xsize/2, rand()%ysize/2, rand()%256);
+ rand();
+ if (i > 1000) break;
+ }
+
+ // restore screen to its original mode
+ VGLEnd();
+ return 0;
+}
diff --git a/share/examples/mdoc/POSIX-copyright b/share/examples/mdoc/POSIX-copyright
new file mode 100644
index 000000000000..144b15559307
--- /dev/null
+++ b/share/examples/mdoc/POSIX-copyright
@@ -0,0 +1,36 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) [year] [your name]
+.\"
+.\" 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.
+.\"
+.\" Portions of this text are reprinted and reproduced in electronic form
+.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology --
+.\" Portable Operating System Interface (POSIX), The Open Group Base
+.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of
+.\" Electrical and Electronics Engineers, Inc and The Open Group. In the
+.\" event of any discrepancy between this version and the original IEEE and
+.\" The Open Group Standard, the original IEEE and The Open Group Standard is
+.\" the referee document. The original Standard can be obtained online at
+.\" http://www.opengroup.org/unix/online.html.
+.\"
diff --git a/share/examples/mdoc/deshallify.sh b/share/examples/mdoc/deshallify.sh
new file mode 100644
index 000000000000..b0493f5033d0
--- /dev/null
+++ b/share/examples/mdoc/deshallify.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+# Script to remove shall clauses.
+#
+#
+sed -e 's/s shall define/s define/g' \
+ -e 's/shall define/defines/g' \
+ -e 's/shall attempt/attempts/g' \
+ -e 's/shall include/includes/g' \
+ -e 's/shall return zero and have/returns zero and has/g' \
+ -e 's/shall return/returns/g' \
+ -e 's/shall also include/also includes/g' \
+ -e 's/pipe or FIFO shall be /pipe of FIFO are /g' \
+ -e 's/s shall be /s are /g' \
+ -e 's/shall be /is /g' \
+ -e 's/s shall create/s create/g' \
+ -e 's/shall create /creates /g' \
+ -e 's/shall perform/performs/g' \
+ -e 's/shall affect the/affect the/g' \
+ -e 's/s shall have/s have/g' \
+ -e 's/shall have/has/g' \
+ -e 's/shall transfer/transfers/g' \
+ -e 's/shall block/blocks/g' \
+ -e 's/shall not block/does not block/g' \
+ -e 's/shall occur/occurs/g' \
+ -e 's/shall complete/complete/g' \
+ -e 's/shall mark for update/marks for update/g' \
+ -e 's/s shall fail/s fail/g' \
+ -e 's/shall fail/fails/g' \
+ -e 's/s shall generate/s generate/g' \
+ -e 's/shall generate/generates/g' \
+ -e 's/shall place/places/g' \
+ -e 's/s shall default/s default/g' \
+ -e 's/shall default/defaults/g' \
+ -e 's/pplications shall ensure/pplications must ensure/g' \
+ -e 's/pplication shall ensure/pplication must ensure/g' \
+ -e 's/shall always begin/always begins/g' \
+ -e 's/s shall begin /s begin /g' \
+ -e 's/shall begin /begins /g' \
+ -e 's/shall always contain /always contains /g' \
+ -e 's/shall produce/produces/g' \
+ -e 's/shall appear/appears/g' \
+ -e 's/s shall be$/s are/g' \
+ -e 's/shall be$/is/g' \
+ -e 's/which shall result /which results /g' \
+ -e 's/s shall not/s are not/g' \
+ -e 's/shall not be/is not/g' \
+ -e 's/shall not/is not/g' \
+ -e 's/s shall behave/s behave/g' \
+ -e 's/shall behave/behaves/g' \
+ -e 's/shall specify/specifies/g' \
+ -e 's/s shall override/s override/g' \
+ -e 's/shall override/overrides/g' \
+ -e 's/shall apply /applies /g' \
+ -e 's/s shall start/s start/g' \
+ -e 's/shall start /starts /g' \
+ -e 's/s shall affect/s affect/g' \
+ -e 's/shall affect/affects/g' \
+ -e 's/s shall indicate/s indicate/g' \
+ -e 's/shall indicate/indicates/g' \
+ -e 's/shall set /set /g' \
+ -e 's/s shall recognize/s recognize/g' \
+ -e 's/shall recognize /recognizes /g' \
+ -e 's/shall also be /is also /g' \
+ -e 's/s shall enter/s enter/g' \
+ -e 's/shall enter /enters /g' \
+ -e 's/shall take /take /g' \
+ -e 's/they shall only take /they only take /g' \
+ -e 's/shall consist /consist /g' \
+ -e 's/s shall cause/s cause/g' \
+ -e 's/shall cause/causes/g' \
+ -e 's/s shall replace/s replace/g' \
+ -e 's/shall replace/replaces/g' \
+ -e 's/shall become/becomes/g' \
+ -e 's/shall each consist/each consist/g' \
+ $1 > $1.x
diff --git a/share/examples/mdoc/example.1 b/share/examples/mdoc/example.1
new file mode 100644
index 000000000000..0bdabe95aa95
--- /dev/null
+++ b/share/examples/mdoc/example.1
@@ -0,0 +1,155 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) [year] [your name]
+.\"
+.\" 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.
+.\"
+.\" Note: The date here should be updated whenever a non-trivial
+.\" change is made to the manual page.
+.Dd December 8, 1999
+.Dt EXAMPLE 1
+.Os
+.Sh NAME
+.Nm example
+.Nd "example command manual page"
+.Sh SYNOPSIS
+.Nm
+.Op Fl abc
+.Op Fl d Ar argument
+.Ar file
+.Sh DESCRIPTION
+This is an example manual page for the
+.Nm
+command.
+It is intended that this example can be used as a template
+when writing a new manual page.
+.Pp
+The options are as follows:
+.Bl -tag -width "-d argument"
+.It Fl a
+Example optional
+.Fl a
+option.
+.It Fl b
+Example optional
+.Fl b
+option.
+.It Fl c
+Example optional
+.Fl c
+option.
+.It Fl d Ar argument
+Example optional
+.Fl d
+option with required argument
+.Ar argument .
+.It Ar file
+Required argument
+.Ar file .
+.El
+.Sh ENVIRONMENT
+The
+.Nm
+command ignores the
+.Ev EXAMPLE
+environment variable.
+.Sh FILES
+.Bl -tag -width "/dev/null" -compact
+.It Pa /dev/null
+Example of a file in the
+.Sx FILES
+section.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+The following is an example of a typical usage
+of the
+.Nm
+command:
+.Pp
+.Dl "example -abc -d xyzzy /dev/null"
+.Sh DIAGNOSTICS
+The command may fail for one of the following reasons:
+.Bl -diag
+.It "example error message"
+An example of an error message.
+.It "another example error message."
+Self explanatory.
+.El
+.Sh COMPATIBILITY
+The
+.Nm
+command has no known compatibility issues.
+.Sh SEE ALSO
+.Xr example 3 ,
+.Xr example 4 ,
+.Xr mdoc 7 ,
+.Xr example 9
+.Rs
+.%A "A. B. Author"
+.%T "Example RFC Title"
+.%O RFC0000
+.Re
+.Rs
+.%A "A. B. Author"
+.%B "Example Book Title"
+.%O ISBN-0-000-00000-0
+.Re
+.Rs
+.%A "A. B. Author"
+.%D "January 1997"
+.%J "Example Journal Name"
+.%T "Example Article Title"
+.Re
+.Sh STANDARDS
+If the command conforms to some standard, such as
+.St -p1003.2
+or
+.St -isoC ,
+it should be noted here.
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 2.2 .
+.Pp
+Some other common
+.Sx HISTORY
+section examples are:
+.Pp
+The
+.Nm
+manual page example first appeared in
+.Bx 4.4 .
+.Pp
+The
+.Nm
+manual page example first appeared in
+.At v6 .
+.Sh AUTHORS
+This
+manual page was written by
+.An Mike Pritchard Aq Mt mpp@FreeBSD.org .
+.Sh BUGS
+The actual code for this command is vaporware.
diff --git a/share/examples/mdoc/example.3 b/share/examples/mdoc/example.3
new file mode 100644
index 000000000000..c4e85062cad1
--- /dev/null
+++ b/share/examples/mdoc/example.3
@@ -0,0 +1,335 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) [year] [your name]
+.\"
+.\" 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.
+.\"
+.\" Note: The date here should be updated whenever a non-trivial
+.\" change is made to the manual page.
+.Dd July 30, 2004
+.Dt EXAMPLE 3
+.Os
+.Sh NAME
+.Nm example
+.Nd "example library function manual page"
+.Sh LIBRARY
+.\" Note: list of available libraries is available in mdoc(7)
+.Lb libc
+.Sh SYNOPSIS
+.In example.h
+.Ft int
+.Fn example "char *ptr" "int mode"
+.Sh DESCRIPTION
+This is an example library function manual page for the
+.Fn example
+function.
+It is intended that this example can be used as a template
+when writing a new manual page.
+.Pp
+The
+.Fn example
+function takes two arguments:
+.Fa ptr
+and
+.Fa mode .
+The argument
+.Fa mode
+may have one of the following values:
+.Bl -tag -width "EXAMPLE_ONE"
+.It Dv EXAMPLE_ONE
+First example of a defined variable.
+.Dv EXAMPLE_ONE
+is described below.
+.It Dv EXAMPLE_TWO
+Second example.
+.El
+.Pp
+The above values are defined in
+.In example.h
+as follows:
+.Bd -literal
+#define EXAMPLE_ONE 1
+#define EXAMPLE_TWO 2
+.Ed
+.Sh IMPLEMENTATION NOTES
+The
+.Fn example
+function is not actually implemented.
+.Sh RETURN VALUES
+.Rv -std example
+.Sh ENVIRONMENT
+The
+.Fn example
+library function ignores the
+.Ev EXAMPLE
+environment variable.
+.Sh FILES
+.Bl -tag -width "/dev/null" -compact
+.It Pa /dev/null
+Example of a file in the
+.Sx FILES
+section.
+.El
+.Sh DIAGNOSTICS
+None.
+.Sh COMPATIBILITY
+The
+.Fn example
+function has no known compatibility issues.
+.Sh ERRORS
+.\" Delete any errno's that are not returned by your
+.\" function or system call and then tailor the
+.\" remaining text as needed.
+The
+.Fn example
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+Operation not permitted.
+.It Bq Er ENOENT
+No such file or directory.
+.It Bq Er ESRCH
+No such process.
+.It Bq Er EINTR
+Interrupted system call.
+.It Bq Er EIO
+Input/output error.
+.It Bq Er ENXIO
+Device not configured.
+.It Bq Er E2BIG
+Argument list too long.
+.It Bq Er ENOEXEC
+Exec format error.
+.It Bq Er EBADF
+Bad file descriptor.
+.It Bq Er ECHILD
+No child processes.
+.It Bq Er EDEADLK
+Resource deadlock avoided.
+.It Bq Er ENOMEM
+Cannot allocate memory.
+.It Bq Er EACCES
+Permission denied.
+.It Bq Er EFAULT
+Bad address.
+.It Bq Er ENOTBLK
+Block device required.
+.It Bq Er EBUSY
+Device busy.
+.It Bq Er EEXIST
+File exists.
+.It Bq Er EXDEV
+Cross-device link.
+.It Bq Er ENODEV
+Operation not supported by device.
+.It Bq Er ENOTDIR
+Not a directory.
+.It Bq Er EISDIR
+Is a directory.
+.It Bq Er EINVAL
+Invalid argument.
+.It Bq Er ENFILE
+Too many open files in system.
+.It Bq Er EMFILE
+Too many open files.
+.It Bq Er ENOTTY
+Inappropriate ioctl for device.
+.It Bq Er ETXTBSY
+Text file busy.
+.It Bq Er EFBIG
+File too large.
+.It Bq Er ENOSPC
+No space left on device.
+.It Bq Er ESPIPE
+Illegal seek.
+.It Bq Er EROFS
+Read-only file system.
+.It Bq Er EMLINK
+Too many links.
+.It Bq Er EPIPE
+Broken pipe.
+.It Bq Er EDOM
+Numerical argument out of domain.
+.It Bq Er ERANGE
+Result too large.
+.It Bq Er EAGAIN
+Resource temporarily unavailable.
+.It Bq Er EWOULDBLOCK
+Operation would block.
+.It Bq Er EINPROGRESS
+Operation now in progress.
+.It Bq Er EALREADY
+Operation already in progress.
+.It Bq Er ENOTSOCK
+Socket operation on non-socket.
+.It Bq Er EDESTADDRREQ
+Destination address required.
+.It Bq Er EMSGSIZE
+Message too long.
+.It Bq Er EPROTOTYPE
+Protocol wrong type for socket.
+.It Bq Er ENOPROTOOPT
+Protocol not available.
+.It Bq Er EPROTONOSUPPORT
+Protocol not supported.
+.It Bq Er ESOCKTNOSUPPORT
+Socket type not supported.
+.It Bq Er EOPNOTSUPP
+Operation not supported.
+.It Bq Er EPFNOSUPPORT
+Protocol family not supported.
+.It Bq Er EAFNOSUPPORT
+Address family not supported by protocol family.
+.It Bq Er EADDRINUSE
+Address already in use.
+.It Bq Er EADDRNOTAVAIL
+Cannot assign requested address.
+.It Bq Er ENETDOWN
+Network is down.
+.It Bq Er ENETUNREACH
+Network is unreachable.
+.It Bq Er ENETRESET
+Network dropped connection on reset.
+.It Bq Er ECONNABORTED
+Software causes connection abort.
+.It Bq Er ENOBUFS
+No buffer space available.
+.It Bq Er EISCONN
+Socket is already connected.
+.It Bq Er ENOTCONN
+Socket is not connected.
+.It Bq Er ESHUTDOWN
+Cannot send after socket shutdown.
+.It Bq Er ETOOMANYREFS
+Too many references: cannot splice.
+.It Bq Er ETIMEDOUT
+Operation timed out.
+.It Bq Er ECONNREFUSED
+Connection refused.
+.It Bq Er ELOOP
+Too many levels of symbolic links.
+.It Bq Er ENAMETOOLONG
+File name too long.
+.It Bq Er EHOSTDOWN
+Host is down.
+.It Bq Er EHOSTUNREACH
+No route to host.
+.It Bq Er ENOTEMPTY
+Directory not empty.
+.It Bq Er EPROCLIM
+Too many processes.
+.It Bq Er EUSERS
+Too many users.
+.It Bq Er EDQUOT
+Disc quota exceeded.
+.It Bq Er ESTALE
+Stale NFS file handle.
+.It Bq Er EREMOTE
+Too many levels of remote in path.
+.It Bq Er EBADRPC
+RPC struct is bad.
+.It Bq Er ERPCMISMATCH
+RPC version wrong.
+.It Bq Er EPROGUNAVAIL
+RPC program not available.
+.It Bq Er EPROGMISMATCH
+Program version wrong.
+.It Bq Er EPROCUNAVAIL
+Bad procedure for program.
+.It Bq Er ENOLCK
+No locks available.
+.It Bq Er ENOSYS
+Function not implemented.
+.It Bq Er EFTYPE
+Inappropriate file type or format.
+.It Bq Er EAUTH
+Authentication error.
+.It Bq Er ENEEDAUTH
+Need authenticator.
+.It Bq Er EIDRM
+Identifier removed.
+.It Bq Er ENOMSG
+No message of desired type.
+.It Bq Er EOVERFLOW
+Value too large to be stored in data type.
+.It Bq Er ECANCELED
+Operation canceled.
+.It Bq Er EILSEQ
+Illegal byte sequence.
+.It Bq Er ENOATTR
+Attribute not found.
+.It Bq Er EDOOFUS
+Programming error.
+.El
+.Sh SEE ALSO
+.Xr example 1 ,
+.Xr example 4 ,
+.Xr mdoc 7 ,
+.Xr example 9
+.Rs
+.%A "A. B. Author"
+.%T "Example RFC Title"
+.%O RFC0000
+.Re
+.Rs
+.%A "A. B. Author"
+.%B "Example Book Title"
+.%O ISBN-0-000-00000-0
+.Re
+.Rs
+.%A "A. B. Author"
+.%D "January 1997"
+.%J "Example Journal Name"
+.%T "Example Article Title"
+.Re
+.Sh STANDARDS
+If the function conforms to some standard, such as
+.St -p1003.1-2004
+or
+.St -isoC-99 ,
+it should be noted here.
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 2.2 .
+.Pp
+Some other common
+.Sx HISTORY
+section examples are:
+.Pp
+The
+.Nm
+manual page example first appeared in
+.Bx 4.4 .
+.Pp
+The
+.Nm
+manual page example first appeared in
+.At v6 .
+.Sh AUTHORS
+This
+manual page was written by
+.An Mike Pritchard Aq Mt mpp@FreeBSD.org .
+.Sh BUGS
+The actual code for this function is vaporware.
diff --git a/share/examples/mdoc/example.4 b/share/examples/mdoc/example.4
new file mode 100644
index 000000000000..47ae5456b79a
--- /dev/null
+++ b/share/examples/mdoc/example.4
@@ -0,0 +1,123 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) [year] [your name]
+.\"
+.\" 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.
+.\"
+.\" Note: The date here should be updated whenever a non-trivial
+.\" change is made to the manual page.
+.Dd July 31, 2015
+.Dt EXAMPLE 4 i386
+.Os
+.Sh NAME
+.Nm example
+.Nd "example device driver manual page"
+.Sh SYNOPSIS
+To compile the driver into the kernel,
+place the following lines in the
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device example"
+.Cd "options EXAMPLE_DEBUG"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+example_load="YES"
+.Ed
+.Sh DESCRIPTION
+This is an example device driver manual page for the
+.Nm
+driver.
+It is intended that this example can be used as a template
+when writing a new manual page.
+.Pp
+The
+.Nm
+driver supports the following ioctls:
+.Bl -tag -width "EIOCNULL"
+.It Dv EIOCEX
+Example ioctl.
+.It Dv EIOCNULL
+Example ioctl.
+.El
+.Pp
+If the kernel is compiled with the
+.Dv EXAMPLE_DEBUG
+option, then additional debugging messages will be displayed.
+.Sh HARDWARE
+The
+.Nm
+driver supports the following example hardware:
+.Pp
+.Bl -bullet -compact
+.It
+Example device 4201
+.It
+Example device 4202
+.El
+.Sh FILES
+.Bl -tag -width "/dev/null" -compact
+.It Pa /dev/null
+Example of a file in the
+.Sx FILES
+section.
+.El
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "example%d: example diagnostic message."
+An example of a diagnostic message.
+.It "example%d: another example diagnostic message."
+Self explanatory.
+.El
+.Sh SEE ALSO
+.Xr example 1 ,
+.Xr example 3 ,
+.Xr mdoc 7 ,
+.Xr example 9
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 2.2 .
+.Pp
+Some other common
+.Sx HISTORY
+section examples are:
+.Pp
+The
+.Nm
+manual page example first appeared in
+.Bx 4.4 .
+.Pp
+The
+.Nm
+manual page example first appeared in
+.At v6 .
+.Sh AUTHORS
+This manual page was written by
+.An Mike Pritchard Aq Mt mpp@FreeBSD.org .
+.Sh BUGS
+The actual code for this device driver is vaporware.
diff --git a/share/examples/mdoc/example.9 b/share/examples/mdoc/example.9
new file mode 100644
index 000000000000..1dd24a99fd42
--- /dev/null
+++ b/share/examples/mdoc/example.9
@@ -0,0 +1,343 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) [year] [your name]
+.\"
+.\" 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.
+.\"
+.\" Note: The date here should be updated whenever a non-trivial
+.\" change is made to the manual page.
+.Dd September 27, 2006
+.Dt EXAMPLE 9
+.Os
+.Sh NAME
+.Nm example
+.Nd "example kernel interface manual page"
+.Sh SYNOPSIS
+.In sys/example.h
+.Ft int
+.Fn example "char *ptr" "int mode"
+.Sh DESCRIPTION
+This is an example manual page for the
+.Fn example
+kernel function.
+It is intended that this example can be used as a template
+when writing a new manual page.
+.Pp
+The
+.Fn example
+function takes two arguments:
+.Fa ptr
+and
+.Fa mode .
+The argument
+.Fa mode
+may have one of the following values:
+.Bl -tag -width "EXAMPLE_ONE"
+.It Dv EXAMPLE_ONE
+First example of a defined variable.
+.Dv EXAMPLE_ONE
+is described below.
+.It Dv EXAMPLE_TWO
+Second example.
+.El
+.Pp
+The above values are defined in
+.In example.h
+as follows:
+.Bd -literal
+#define EXAMPLE_ONE 1
+#define EXAMPLE_TWO 2
+.Ed
+.Sh IMPLEMENTATION NOTES
+The
+.Fn example
+function is not actually implemented.
+.Sh LOCKING
+The
+.Va example_lock
+lock must be held before
+.Fn example
+is called.
+.Pp
+Since
+.Va example_lock
+is a
+.Xr mutex 9 ,
+no sleepable locks (i.e.,
+.Xr sx 9
+locks) can be acquired in
+.Fn example .
+.Sh RETURN VALUES
+The
+.Fn example
+function returns the value 0 if successful;
+otherwise one of the values listed in the
+.Sx ERRORS
+section is returned, to indicate the error.
+.Sh EXAMPLES
+.Bd -literal
+ int error;
+
+ mtx_lock(&example_lock);
+ if ((error = example(NULL, EXAMPLE_ONE)) != 0) {
+ mtx_unlock(&example_lock);
+ return (error);
+ }
+ mtx_unlock(&example_lock);
+.Ed
+.Sh COMPATIBILITY
+The
+.Fn example
+function has no known compatibility issues.
+.Sh ERRORS
+.\" Delete any errno's that are not returned by your
+.\" function or system call and then tailor the
+.\" remaining text as needed.
+The
+.Fn example
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+Operation not permitted.
+.It Bq Er ENOENT
+No such file or directory.
+.It Bq Er ESRCH
+No such process.
+.It Bq Er EINTR
+Interrupted system call.
+.It Bq Er EIO
+Input/output error.
+.It Bq Er ENXIO
+Device not configured.
+.It Bq Er E2BIG
+Argument list too long.
+.It Bq Er ENOEXEC
+Exec format error.
+.It Bq Er EBADF
+Bad file descriptor.
+.It Bq Er ECHILD
+No child processes.
+.It Bq Er EDEADLK
+Resource deadlock avoided.
+.It Bq Er ENOMEM
+Cannot allocate memory.
+.It Bq Er EACCES
+Permission denied.
+.It Bq Er EFAULT
+Bad address.
+.It Bq Er ENOTBLK
+Block device required.
+.It Bq Er EBUSY
+Device busy.
+.It Bq Er EEXIST
+File exists.
+.It Bq Er EXDEV
+Cross-device link.
+.It Bq Er ENODEV
+Operation not supported by device.
+.It Bq Er ENOTDIR
+Not a directory.
+.It Bq Er EISDIR
+Is a directory.
+.It Bq Er EINVAL
+Invalid argument.
+.It Bq Er ENFILE
+Too many open files in system.
+.It Bq Er EMFILE
+Too many open files.
+.It Bq Er ENOTTY
+Inappropriate ioctl for device.
+.It Bq Er ETXTBSY
+Text file busy.
+.It Bq Er EFBIG
+File too large.
+.It Bq Er ENOSPC
+No space left on device.
+.It Bq Er ESPIPE
+Illegal seek.
+.It Bq Er EROFS
+Read-only file system.
+.It Bq Er EMLINK
+Too many links.
+.It Bq Er EPIPE
+Broken pipe.
+.It Bq Er EDOM
+Numerical argument out of domain.
+.It Bq Er ERANGE
+Result too large.
+.It Bq Er EAGAIN
+Resource temporarily unavailable.
+.It Bq Er EWOULDBLOCK
+Operation would block.
+.It Bq Er EINPROGRESS
+Operation now in progress.
+.It Bq Er EALREADY
+Operation already in progress.
+.It Bq Er ENOTSOCK
+Socket operation on non-socket.
+.It Bq Er EDESTADDRREQ
+Destination address required.
+.It Bq Er EMSGSIZE
+Message too long.
+.It Bq Er EPROTOTYPE
+Protocol wrong type for socket.
+.It Bq Er ENOPROTOOPT
+Protocol not available.
+.It Bq Er EPROTONOSUPPORT
+Protocol not supported.
+.It Bq Er ESOCKTNOSUPPORT
+Socket type not supported.
+.It Bq Er EOPNOTSUPP
+Operation not supported.
+.It Bq Er EPFNOSUPPORT
+Protocol family not supported.
+.It Bq Er EAFNOSUPPORT
+Address family not supported by protocol family.
+.It Bq Er EADDRINUSE
+Address already in use.
+.It Bq Er EADDRNOTAVAIL
+Cannot assign requested address.
+.It Bq Er ENETDOWN
+Network is down.
+.It Bq Er ENETUNREACH
+Network is unreachable.
+.It Bq Er ENETRESET
+Network dropped connection on reset.
+.It Bq Er ECONNABORTED
+Software causes connection abort.
+.It Bq Er ENOBUFS
+No buffer space available.
+.It Bq Er EISCONN
+Socket is already connected.
+.It Bq Er ENOTCONN
+Socket is not connected.
+.It Bq Er ESHUTDOWN
+Cannot send after socket shutdown.
+.It Bq Er ETOOMANYREFS
+Too many references: cannot splice.
+.It Bq Er ETIMEDOUT
+Operation timed out.
+.It Bq Er ECONNREFUSED
+Connection refused.
+.It Bq Er ELOOP
+Too many levels of symbolic links.
+.It Bq Er ENAMETOOLONG
+File name too long.
+.It Bq Er EHOSTDOWN
+Host is down.
+.It Bq Er EHOSTUNREACH
+No route to host.
+.It Bq Er ENOTEMPTY
+Directory not empty.
+.It Bq Er EPROCLIM
+Too many processes.
+.It Bq Er EUSERS
+Too many users.
+.It Bq Er EDQUOT
+Disc quota exceeded.
+.It Bq Er ESTALE
+Stale NFS file handle.
+.It Bq Er EREMOTE
+Too many levels of remote in path.
+.It Bq Er EBADRPC
+RPC struct is bad.
+.It Bq Er ERPCMISMATCH
+RPC version wrong.
+.It Bq Er EPROGUNAVAIL
+RPC program not available.
+.It Bq Er EPROGMISMATCH
+Program version wrong.
+.It Bq Er EPROCUNAVAIL
+Bad procedure for program.
+.It Bq Er ENOLCK
+No locks available.
+.It Bq Er ENOSYS
+Function not implemented.
+.It Bq Er EFTYPE
+Inappropriate file type or format.
+.It Bq Er EAUTH
+Authentication error.
+.It Bq Er ENEEDAUTH
+Need authenticator.
+.It Bq Er EIDRM
+Identifier removed.
+.It Bq Er ENOMSG
+No message of desired type.
+.It Bq Er EOVERFLOW
+Value too large to be stored in data type.
+.It Bq Er ECANCELED
+Operation canceled.
+.It Bq Er EILSEQ
+Illegal byte sequence.
+.It Bq Er ENOATTR
+Attribute not found.
+.It Bq Er EDOOFUS
+Programming error.
+.El
+.Sh SEE ALSO
+.Xr example 1 ,
+.Xr example 3 ,
+.Xr example 4 ,
+.Xr mdoc 7 ,
+.Xr mutex 9
+.Rs
+.%A "A. B. Author"
+.%T "Example RFC Title"
+.%O RFC0000
+.Re
+.Rs
+.%A "A. B. Author"
+.%B "Example Book Title"
+.%O ISBN-0-000-00000-0
+.Re
+.Rs
+.%A "A. B. Author"
+.%D "January 1997"
+.%J "Example Journal Name"
+.%T "Example Article Title"
+.Re
+.Sh HISTORY
+The
+.Nm
+manual page example first appeared in
+.Fx 6.0 .
+.Pp
+Some other common
+.Sx HISTORY
+section examples are:
+.Pp
+The
+.Nm
+manual page example first appeared in
+.Bx 4.4 .
+.Pp
+The
+.Nm
+manual page example first appeared in
+.At v6 .
+.Sh AUTHORS
+This
+manual page was written by
+.An Giorgos Keramidas Aq Mt keramida@FreeBSD.org .
+.Sh BUGS
+The actual code for this function is vaporware.
diff --git a/share/examples/modules/Makefile b/share/examples/modules/Makefile
new file mode 100644
index 000000000000..0f0a2fb01e8a
--- /dev/null
+++ b/share/examples/modules/Makefile
@@ -0,0 +1,6 @@
+.PATH: ${SRCTOP}/sys/skel
+
+KMOD= skel
+SRCS= skel.c
+
+.include <bsd.kmod.mk>
diff --git a/share/examples/modules/skel.c b/share/examples/modules/skel.c
new file mode 100644
index 000000000000..3c2cbd8eb8b1
--- /dev/null
+++ b/share/examples/modules/skel.c
@@ -0,0 +1,86 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 George V. Neville-Neil
+ *
+ * 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.
+ *
+ */
+
+/*
+ * SKEL Loadable Kernel Module for the FreeBSD Operating System
+ *
+ * The SKEL module is meant to act as a skeleton for creating new
+ * kernel modules.
+ *
+ * This module can be loaded and unloaded from * FreeBSD and is for
+ * use in teaching as well.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+
+/*
+ * Every module can have a module specific piece of code that is
+ * executed whenever the module is loaded or unloaded. The following
+ * is a trivial example that prints a message on the console whenever
+ * the module is loaded or unloaded.
+ */
+
+static int
+skel_mod_event(module_t mod, int type, void *data)
+{
+
+ switch (type) {
+ case MOD_LOAD:
+ printf("SKEL module loading.\n");
+ return (0);
+ case MOD_UNLOAD:
+ printf("SKEL module unloading.\n");
+ return (0);
+ }
+ return (EOPNOTSUPP);
+}
+
+/*
+ * Modules can have associated data and the module data also contains
+ * an entry for the function called by the kernel on load and unload.
+ */
+
+static moduledata_t skel_mod = {
+ "skel",
+ skel_mod_event,
+ NULL,
+};
+
+/*
+ * Each module is declared with its name and module data. The
+ * ordering arguments at the end put this module into the device
+ * driver class, which is sufficient for our needs. The complete list
+ * of modules types and ording can be found in sys/kernel.h
+ */
+
+DECLARE_MODULE(skel, skel_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
+
diff --git a/share/examples/netgraph/ether.bridge b/share/examples/netgraph/ether.bridge
new file mode 100644
index 000000000000..6a9dd5c36c6e
--- /dev/null
+++ b/share/examples/netgraph/ether.bridge
@@ -0,0 +1,169 @@
+#!/bin/sh
+# This script sets up an Ethernet bridging network across multiple
+# Ethernet interfaces using the ng_bridge(4) and ng_ether(4) netgraph
+# node types.
+#
+# To use this script:
+#
+# 0. Make your own copy of this example script.
+#
+# 1. Give your bridging network a name by editing the definition of
+# ${BRIDGE_NAME} below. It must be a valid netgraph node name.
+#
+# 2. Edit the definitions of ${BRIDGE_IFACES} and ${LOCAL_IFACES}
+# as described below to define your bridging interfaces.
+#
+# 3. Run this script with "start" as the command line argument.
+#
+# 4. Examine bridging statistics by running this script with "stats"
+# as the command line argument.
+#
+# 5. Stop bridging by running this script with "stop" as the
+# command line argument.
+#
+# To run multiple independent bridging networks, create multiple
+# copies of this script with different variable definitions.
+#
+# To make a "brouted" network, with IP being routed and other protocols being
+# bridged, add all the interface in the BRIDGE_IFACES to the LOCAL_IFACES.
+# If you just want a normal bridge, just one will be enough.
+# In some cases you may want some combination.
+#
+
+# Give each bridging network a unique name here.
+
+BRIDGE_NAME="bnet0"
+
+# List the names of the interfaces that you want to bridge across
+# here in ${BRIDGE_IFACES}. If you want to include the local host
+# machine as well then set ${LOCAL_IFACES} as well (they may also be
+# listed in ${BRIDGE_IFACES}). Of course, any ${LOCAL_IFACE} must
+# be ifconfig(8)ured separately. If you don't want a ${LOCAL_IFACE}
+# then assign it the empty string.
+
+BRIDGE_IFACES="de0 fxp0 fxp1"
+LOCAL_IFACES="fxp0 fxp1"
+
+#####################################################################
+#### Everything below this point should not need to be modified. ####
+#####################################################################
+
+# Routine to verify node's existence.
+bridge_verify() {
+ ngctl info ${BRIDGE_NAME}: >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "${BRIDGE_NAME}: bridge network not found"
+ exit 1
+ fi
+}
+
+# Routine to get and display link stats.
+bridge_linkstats() {
+ STATS=`ngctl msg ${BRIDGE_NAME}: getstats $1`
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ echo "${STATS}" | fmt 2 | awk '/=/ { fl=index($0, "="); \
+ printf "%20s = %s\n", substr($0, 0, fl - 1), substr($0, fl + 1); }'
+}
+
+# Start/restart routine.
+bridge_start() {
+
+ # Load netgraph KLD's as necessary.
+ for KLD in ng_ether ng_bridge; do
+ if ! kldstat -v | grep -qw ${KLD}; then
+ echo -n "Loading ${KLD}.ko... "
+ kldload ${KLD} || exit 1
+ echo "done"
+ fi
+ done
+
+ # Reset all interfaces.
+ bridge_stop
+
+ # Verify all interfaces exist.
+ for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do
+ if ! ngctl info ${ETHER}: >/dev/null 2>&1; then
+ echo "Error: interface ${ETHER} does not exist"
+ exit 1
+ fi
+ ifconfig ${ETHER} up || exit 1
+ done
+
+ # Create new ng_bridge(4) node, attached to the first interface.
+ FIRSTIF=`echo ${BRIDGE_IFACES} | awk '{ print $1 }'`
+ ngctl mkpeer ${FIRSTIF}: bridge lower link0 || exit 1
+ ngctl name ${FIRSTIF}:lower ${BRIDGE_NAME} || exit 1
+
+ # Attach other interfaces as well.
+ LINKNUM=0
+ for ETHER in ${BRIDGE_IFACES}; do
+ if [ ${LINKNUM} != 0 ]; then
+ ngctl connect ${ETHER}: ${BRIDGE_NAME}: \
+ lower link${LINKNUM} || exit 1
+ fi
+ LINKNUM=`expr ${LINKNUM} + 1`
+ done
+
+ # Hook up local interface, if any.
+ for LOCAL_IFACE in ${LOCAL_IFACES}; do
+ ngctl connect ${LOCAL_IFACE}: ${BRIDGE_NAME}: \
+ upper link${LINKNUM} || exit 1
+ LINKNUM=`expr ${LINKNUM} + 1`
+ done
+
+ # Set all interfaces in promiscuous mode and don't overwrite src addr.
+ for ETHER in ${BRIDGE_IFACES}; do
+ ngctl msg ${ETHER}: setpromisc 1 || exit 1
+ ngctl msg ${ETHER}: setautosrc 0 || exit 1
+ done
+}
+
+# Stop routine.
+bridge_stop() {
+ ngctl kill ${BRIDGE_NAME}: >/dev/null 2>&1
+ for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do
+ ngctl kill ${ETHER}: >/dev/null 2>&1
+ done
+}
+
+# Stats routine.
+bridge_stats() {
+
+ # Make sure node exists.
+ bridge_verify
+
+ echo ""
+ echo "Statistics for bridging network ${BRIDGE_NAME}:"
+ echo ""
+ LINKNUM=0
+ for ETHER in ${BRIDGE_IFACES}; do
+ echo "Network interface ${ETHER}:"
+ bridge_linkstats ${LINKNUM}
+ LINKNUM=`expr ${LINKNUM} + 1`
+ done
+ for LOCAL_IFACE in ${LOCAL_IFACES}; do
+ echo "Local host interface ${LOCAL_IFACE}:"
+ bridge_linkstats ${LINKNUM}
+ LINKNUM=`expr ${LINKNUM} + 1`
+ done
+}
+
+# Main entry point.
+case $1 in
+ start)
+ bridge_start
+ ;;
+ stats)
+ bridge_verify
+ bridge_stats
+ ;;
+ stop)
+ bridge_verify
+ bridge_stop
+ ;;
+ *)
+ echo "usage: $0 [ start | stop | stats ]"
+ exit 1
+esac
diff --git a/share/examples/netgraph/frame_relay b/share/examples/netgraph/frame_relay
new file mode 100644
index 000000000000..0113f76076da
--- /dev/null
+++ b/share/examples/netgraph/frame_relay
@@ -0,0 +1,45 @@
+#!/bin/sh
+# script to set up a frame relay link on the sr card.
+# The dlci used is selected below. The default is 16
+
+CARD=sr0
+DLCI=16
+
+# create a frame_relay type node and attach it to the sync port.
+ngctl mkpeer ${CARD}: frame_relay rawdata downstream
+
+# Attach the dlci output of the (de)multiplexor to a new
+# Link management protocol node.
+ngctl mkpeer ${CARD}:rawdata lmi dlci0 auto0
+
+# Also attach dlci 1023, as it needs both to try auto-configuring.
+# The Link management protocol is now alive and probing..
+ngctl connect ${CARD}:rawdata ${CARD}:rawdata.dlci0 dlci1023 auto1023
+
+# Attach the DLCI(channel) the Telco has assigned you to
+# a node to handle whatever protocol encapsulation your peer
+# is using. In this case RFC1490 encapsulation.
+ngctl mkpeer ${CARD}:rawdata rfc1490 dlci${DLCI} downstream
+
+
+# Attach the ip (inet) protocol output of the protocol mux to the ip (inet)
+# input of a netgraph "interface" node (ifconfig should show it as "ng0").
+#if interface ng0 needs to be created use a mkpeer command.. e.g.
+ngctl mkpeer ${CARD}:rawdata.dlci${DLCI} iface inet inet
+
+# if ng0 already exists, use a CONNECT command instead of a mkpeer. e.g.
+# ngctl connect ${CARD}:rawdata.dlci${DLCI} ng0: inet inet
+
+# Then use ifconfig on interface ng0 as usual
+
+# A variant on this whole set might use the 'name' command to make it more
+# readable. But it doesn't work if you have multiple lines or dlcis
+# e.g.
+# ngctl mkpeer ${CARD}: frame_relay rawdata downstream
+# ngctl name ${CARD}:rawdata mux
+# ngctl mkpeer mux: lmi dlci0 auto0
+# ngctl name mux:dlci0 lmi
+# ngctl connect mux: lmi: dlci1023 auto1023
+# ngctl mkpeer mux: rfc1490 dlci${DLCI} downstream
+# ngctl mux:dlci${DLCI} protomux
+# ngctl mkpeer protomux: iface inet inet
diff --git a/share/examples/netgraph/ngctl b/share/examples/netgraph/ngctl
new file mode 100644
index 000000000000..c879cbea7b0f
--- /dev/null
+++ b/share/examples/netgraph/ngctl
@@ -0,0 +1,172 @@
+
+#
+# This is an example that shows how to send ASCII formatted control
+# messages to a node using ngctl(8).
+#
+# What we will do here create a divert(4) tap. This simply dumps
+# out all packets diverted by some ipfw(8) divert rule to the console.
+#
+# Lines that begin with ``$'' (shell prompt) or ``+'' (ngctl prompt)
+# indicate user input
+#
+
+# First, start up ngctl in interactive mode:
+
+ $ ngctl
+ Available commands:
+ connect Connects hook <peerhook> of the node at <relpath> to <hook>
+ debug Get/set debugging verbosity level
+ help Show command summary or get more help on a specific command
+ list Show information about all nodes
+ mkpeer Create and connect a new node to the node at "path"
+ msg Send a netgraph control message to the node at "path"
+ name Assign name <name> to the node at <path>
+ read Read and execute commands from a file
+ rmhook Disconnect hook "hook" of the node at "path"
+ show Show information about the node at <path>
+ shutdown Shutdown the node at <path>
+ status Get human readable status information from the node at <path>
+ types Show information about all installed node types
+ quit Exit program
+ +
+
+# Now let's create a ng_ksocket(4) node, in the family PF_DIVERT,
+# of type SOCK_RAW:
+
+ + mkpeer ksocket foo divert/raw/0
+
+# Note that ``foo'' is the hook name on the socket node, which can be
+# anything. The ``inet/raw/divert'' is the hook name on the ksocket
+# node, which tells it what kind of socket to create.
+
+# Lets give our ksocket node a global name. How about ``fred'':
+
+ + name foo fred
+
+# Note that we used ngctl's ``name'' command to do this. However,
+# the following manually constructed netgraph message would have
+# accomplished the exact same thing:
+
+ + msg foo name { name="fred" }
+
+# Here we are using the ASCII <-> binary control message conversion
+# routines. ngctl does this for us automatically when we use the
+# ``msg'' command.
+
+# Now lets bind the socket associated with the ksocket node to a port
+# supplied by the system. We do this by sending the ksocket node a
+# ``bind'' control message. Again, ngctl does the conversion of the
+# control message from ASCII to binary behind the scenes.
+
+ + msg fred: bind inet/192.168.1.1
+
+# The ksocket accepts arbitrary sockaddr structures, but also has
+# special support for the PF_LOCAL and PF_INET protocol families.
+# That is why we can specify the struct sockaddr argument to the
+# ``bind'' command as ``inet/192.168.1.1'' (since we didn't specify
+# a port number, it's assumed to be zero). We could have also
+# relied on the generic sockaddr syntax and instead said this:
+
+ + msg fred: bind { family=2 len=16 data=[ 2=192 168 1 1 ] }
+
+# This is what you would have to do for protocol families other
+# that PF_INET and PF_LOCAL, at least until special handling for
+# new ones is added.
+
+# The reason for the ``2=192'' is to skip the two byte IP port number,
+# which causes it to be set to zero, the default value for integral
+# types when parsing. Now since we didn't ask for a specific port
+# number, we need to do a ``getname'' to see what port number we got:
+
+ + msg fred: getname
+ Rec'd response "getname" (5) from "fred:":
+ Args: inet/192.168.1.1:1029
+
+# As soon as we sent the message, we got back a response. Here
+# ngctl is telling us that it received a control message with the
+# NGF_RESP (response) flag set, the response was to a prior ``getname''
+# control message, that the originator was the node addressable
+# as ``fred:''. The message arguments field is then displayed to
+# us in its ASCII form. In this case, what we get back is a struct
+# sockaddr, and there we see that our port number is 1029.
+
+# So now let's add the ipfw divert rule for whatever packets we
+# want to see. How about anything from 192.168.1.129.
+
+ + ^Z
+ Suspended
+ $ ipfw add 100 divert 1029 ip from 192.168.1.129 to any
+ 00100 divert 1029 ip from 192.168.1.129 to any
+ $ fg
+
+# Now watch what happens when we try to ping from that machine:
+
+ +
+ Rec'd data packet on hook "foo":
+ 0000: 45 00 00 3c 57 00 00 00 20 01 bf ee c0 a8 01 81 E..<W... .......
+ 0010: c0 a8 01 01 08 00 49 5c 03 00 01 00 61 62 63 64 ......I\....abcd
+ 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst
+ 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi
+ +
+ Rec'd data packet on hook "foo":
+ 0000: 45 00 00 3c 58 00 00 00 20 01 be ee c0 a8 01 81 E..<X... .......
+ 0010: c0 a8 01 01 08 00 48 5c 03 00 02 00 61 62 63 64 ......H\....abcd
+ 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst
+ 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi
+ +
+ Rec'd data packet on hook "foo":
+ 0000: 45 00 00 3c 59 00 00 00 20 01 bd ee c0 a8 01 81 E..<Y... .......
+ 0010: c0 a8 01 01 08 00 47 5c 03 00 03 00 61 62 63 64 ......G\....abcd
+ 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst
+ 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi
+ +
+
+# So we're seeing the output from the ksocket socket appear on the ``foo''
+# hook of ngctl's socket node. Since the packets are getting diverted,
+# the 192.168.1.129 machine doesn't see any response from us.
+
+# Of course, any type of socket can be used, even TCP:
+
+ + mkpeer ksocket bar inet/stream/tcp
+ + msg bar connect inet/192.168.1.33:13
+ ngctl: send msg: Operation now in progress
+ +
+ Rec'd data packet on hook "foo":
+ 0000: 4d 6f 6e 20 4e 6f 76 20 32 39 20 31 37 3a 34 38 Mon Nov 29 17:48
+ 0010: 3a 33 37 20 31 39 39 39 0d 0a :37 1999..
+ +
+
+# Or, UNIX domain:
+
+ + mkpeer ksocket bar local/stream/0
+ + msg bar bind local/"/tmp/bar.socket"
+ +
+
+# Here's an example of a more complicated ASCII control message argument.
+# If you look in /sys/netgraph/ng_message.h, you will see that a node
+# responds to a NGM_LISTHOOKS with a struct hooklist, which contains
+# an array of struct linkinfo:
+#
+# /* Structure used for NGM_LISTHOOKS */
+# struct linkinfo {
+# char ourhook[NG_HOOKSIZ]; /* hook name */
+# char peerhook[NG_HOOKSIZ]; /* peer hook */
+# struct nodeinfo nodeinfo;
+# };
+#
+# struct hooklist {
+# struct nodeinfo nodeinfo; /* node information */
+# struct linkinfo link[0]; /* info about each hook */
+# };
+#
+# By sending a node the ``listhooks'' command using ngctl, we can see
+# this structure in ASCII form (lines wrapped for readability):
+
+ + msg bar bind local/"/tmp/bar.socket"
+ + msg bar listhooks
+ Rec'd response "listhooks" (7) from "bar":
+ Args: { nodeinfo={ type="ksocket" id=9 hooks=1 }
+ linkinfo=[ { ourhook="local/stream/0" peerhook="bar"
+ nodeinfo={ name="ngctl1327" type="socket" id=8 hooks=1 } } ] }
+
+
diff --git a/share/examples/netgraph/raw b/share/examples/netgraph/raw
new file mode 100644
index 000000000000..44196780fd0c
--- /dev/null
+++ b/share/examples/netgraph/raw
@@ -0,0 +1,15 @@
+#!/bin/sh
+# script to connect a raw synchronous card to a system interface.
+# Assumes the file if_sr was compiled with options NETGRAPH.
+
+CARD=sr0
+
+# create an interface "ng0" and attach it to the sync port.
+# The packets had jolly well better be IP because we are not discriminating.
+ngctl mkpeer ${CARD}: iface rawdata inet
+
+# if ng0 already exists, use a CONNECT command instead of a mkpeer. e.g.
+# ngctl connect ${CARD}: ng0: rawdata inet
+
+# Then use ifconfig on interface ng0 as usual
+
diff --git a/share/examples/netgraph/udp.tunnel b/share/examples/netgraph/udp.tunnel
new file mode 100644
index 000000000000..fb589ed7e15f
--- /dev/null
+++ b/share/examples/netgraph/udp.tunnel
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+# This script sets up a virtual point-to-point WAN link between
+# two subnets, using UDP packets as the ``WAN connection.''
+# The two subnets might be non-routable addresses behind a
+# firewall.
+#
+
+# Here define the local and remote inside networks as well
+# as the local and remote outside IP addresses and UDP port
+# number that will be used for the tunnel.
+#
+LOC_INTERIOR_IP=192.168.1.1
+LOC_EXTERIOR_IP=1.1.1.1
+REM_INTERIOR_IP=192.168.2.1
+REM_EXTERIOR_IP=2.2.2.2
+REM_INSIDE_NET=192.168.2.0
+UDP_TUNNEL_PORT=4028
+
+# Create the interface node ``ng0'' if it doesn't exist already,
+# otherwise just make sure it's not connected to anything.
+# In FreeBSD, interfaces cannot be removed so it might already
+# be there from before.
+#
+if ifconfig ng0 >/dev/null 2>&1; then
+ ifconfig ng0 inet down delete >/dev/null 2>&1
+ ngctl shutdown ng0:
+else
+ ngctl mkpeer iface dummy inet
+fi
+
+# Attach a UDP socket to the ``inet'' hook of the interface node
+# using the ng_ksocket(4) node type.
+#
+ngctl mkpeer ng0: ksocket inet inet/dgram/udp
+
+# Bind the UDP socket to the local external IP address and port
+#
+ngctl msg ng0:inet bind inet/${LOC_EXTERIOR_IP}:${UDP_TUNNEL_PORT}
+
+# Connect the UDP socket to the peer's external IP address and port
+#
+ngctl msg ng0:inet connect inet/${REM_EXTERIOR_IP}:${UDP_TUNNEL_PORT}
+
+# Configure the point-to-point interface
+#
+ifconfig ng0 ${LOC_INTERIOR_IP} ${REM_INTERIOR_IP}
+
+# Add a route to the peer's interior network via the tunnel
+#
+route add ${REM_INSIDE_NET} ${REM_INTERIOR_IP}
+
diff --git a/share/examples/netgraph/virtual.chain b/share/examples/netgraph/virtual.chain
new file mode 100644
index 000000000000..615f7da20a52
--- /dev/null
+++ b/share/examples/netgraph/virtual.chain
@@ -0,0 +1,369 @@
+#!/bin/sh
+#
+# Copyright (c) 2010, Yavuz Gokirmak
+#
+# All rights reserved.
+#
+# This source code may be used, modified, copied, distributed, and
+# sold, in both source and binary form provided that the above
+# copyright and these terms are retained, verbatim, as the first
+# lines of this file. Under no circumstances is the author
+# responsible for the proper functioning of the software nor does
+# the author assume any responsibility for damages incurred with
+# its use.
+#
+#
+# This script creates and connects n router like nodes. Complex wide
+# area topologies can be created with the help of script.
+#
+# Virtual nodes are generated via jails and network connections are
+# established using ng_eiface(4) node types.
+#
+# To use this script:
+#
+# 0. Make your own copy of this example script.
+#
+# 1. Edit the definition of ${TARGET_TOPOLOGY} to define your virtual
+# nodes. Virtual topology definition includes node names and their
+# IP address. Target top. syntax: ( name|ip<->name|ip ... )
+# Example 1: ( n1|10.0.2.1/30<->n2|10.0.2.2/30 ...)
+# Example 2: ( n1|2001:b90::14a/125<->n1|2001:b90::14b/125 ...)
+#
+# 2. Run this script with "start" as the command line argument.
+#
+# 3. Add necessary static route commands for each virtual node. For
+# example assume you have three virtual nodes connected each other
+# like a chain (n1 is connected to n2, n2 is connected to n3).
+# In order to establish connectivity among these virtual nodes,
+# you have to add default routes to node n1 and node n3. Example
+# static route command is:
+# STATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2"
+# STATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5"
+# After defining default routes with above format you have to set
+# the total number of static route commands as:
+# STATIC_ROUTE_CNT=2
+#
+# 4. Stop bridging by running this script with "stop" as the
+# command line argument.
+#
+# 5. This script uses a template file in order to carry information
+# between start and stop calls.
+# In the start call, the netgraph interfaces and jails are created.
+# At the stop phase, all created objects should be removed.
+# DO NOT delete the temporary file between the start and stop phases.
+#
+# Target Topology:
+#
+# +---------------+ +---------------------------------------------+
+# | n1 (vimage) | | n2 (vimage) |
+# | | | |
+# | +-----------+ | | +-----------+ +-----------+ +-----------+ |
+# | | ngeth0 | | | | ngeth1 | | ngeth2 | | ngeth4 | |
+# | |(ng_eiface)| | | |(ng_eiface)| |(ng_eiface)| |(ng_eiface)| |
+# | +--+-----+--+ | | +--+-----+--+ +--+-----+--+ +--+-----+--+ |
+# | |ether| | | |ether| |ether| |ether| |
+# | +-X---+ | | +--X--+ +--X--+ +--X--+ |
+# +-------X-------+ +------X--------------X---------------X-------+
+# X X X X
+# X X X X
+# XXXXXXXXXXXXXXX X X
+# X X
+# +--------X------+ +--------X------+
+# | -+--X--+- | | -+--X--+- |
+# | |ether| | | |ether| |
+# | +--+-----+--+ | | +--+-----+--+ |
+# | | ngeth3 | | | | ngeth5 | |
+# | |(ng_eiface)| | | |(ng_eiface)| |
+# | +-----------+ | | +-----------+ |
+# | | | |
+# | n3 (vimage) | | n4 (vimage) |
+# +---------------+ +---------------+
+#
+#
+#
+
+# List the names of virtual nodes and their IP addresses. Use ':'
+# character to separate node name from node IP address and netmask.
+
+TARGET_TOPOLOGY="n1|10.0.2.1/30<->n2|10.0.2.2/30 n2|10.0.2.5/30<->n3|10.0.2.6/30 n2|10.0.2.9/30<->n4|10.0.2.10/30"
+STATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2"
+STATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5"
+STATIC_ROUTE2="jexec n4 route add -inet default 10.0.2.9"
+STATIC_ROUTE_CNT=3
+
+# MAC manufacturer prefix. This can be modified according to needs.
+MAC_PREFIX="00:1d:92"
+
+# Temporary file is important for proper execution of script.
+TEMP_FILE="/var/tmp/.virtual.chain.tmp"
+
+# Set root directory for jails to be created.
+JAIL_PATH="/usr/jails/router"
+
+
+####################################################################
+#### Nothing below this point should need to be modified. ####
+####################################################################
+
+
+# Start/restart routine.
+virtual_chain_start() {
+
+ # Load netgraph KLD's as necessary.
+
+ for KLD in ng_ether ng_bridge ng_eiface; do
+ if ! kldstat -v | grep -qw ${KLD}; then
+ echo -n "Loading ${KLD}.ko... "
+ kldload ${KLD} || exit 1
+ echo "done"
+ fi
+ done
+
+ # Reset all interfaces and jails. If temporary file can not be found
+ # script assumes that there is no previous configuration.
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo "No previous configuration(${TEMP_FILE}) found to clean-up."
+ else
+ echo -n "Cleaning previous configuration..."
+ virtual_chain_stop
+ echo "done"
+ fi
+
+ # Create temporary file for usage. This file includes generated
+ # interface names and jail names. All bridges, interfaces and jails
+ # are written to file while created. In clean-up process written
+ # objects are cleaned (i.e. removed) from system.
+
+ if [ -e ${TEMP_FILE} ]; then
+ touch ${TEMP_FILE}
+ fi
+
+
+ # Attach other interfaces as well.
+ for CONNECTION in ${TARGET_TOPOLOGY}; do
+
+ # Virtual connections are defined in TARGET_TOPOLOGY variable.
+ # They have the form of 'nodeName|IPaddr'. Below two lines split
+
+ PEER1=`echo ${CONNECTION} | awk -F"<->" '{print $1}'`
+ PEER1_NAME=`echo ${PEER1} | awk -F"|" '{print $1}'`
+ PEER1_IP=`echo ${PEER1} | awk -F"|" '{print $2}'`
+
+ PEER2=`echo ${CONNECTION} | awk -F"<->" '{print $2}'`
+ PEER2_NAME=`echo ${PEER2} | awk -F"|" '{print $1}'`
+ PEER2_IP=`echo ${PEER2} | awk -F"|" '{print $2}'`
+
+ # !!! if not created already..
+ # Create virtual node (jail) with given name and using
+ # JAIL_PATH as root directory for jail.
+
+ virtual_chain_create_peer_if_necessary ${PEER1_NAME}
+ virtual_chain_create_peer_if_necessary ${PEER2_NAME}
+
+ # create an interface for peer with the given peer IP. Get interface
+ # for future use; you will connect this interface to the other
+ # peers' (PEER2) interface.
+ virtual_chain_create_interface_with_ip ${PEER1_NAME} ${PEER1_IP}
+ PEER1_INTERFACE=${RET_INTERFACE}
+
+ # create an interface for peer with the given peer IP. Get interface
+ # for future use; you will connect this interface to the other
+ # peers' (PEER2) interface.
+ virtual_chain_create_interface_with_ip ${PEER2_NAME} ${PEER2_IP}
+ PEER2_INTERFACE=${RET_INTERFACE}
+
+ # Connect virtual interface to other interface. Syntax is :
+ # ngctl connect INTERFACE1: INTERFACE2: ether ether.
+
+ echo -n "Connecting ${PEER1_INTERFACE}:ether to ${PEER2_INTERFACE}:ether..."
+ ngctl connect ${PEER1_INTERFACE}: ${PEER2_INTERFACE}: ether ether \
+ || exit 1
+ echo "done"
+
+ done
+
+ # Executes static route add commands.
+ i=0
+ while [ $i != $STATIC_ROUTE_CNT ]; do
+ eval ROUTE=\${STATIC_ROUTE${i}}
+ ret=`${ROUTE}`
+ i=`expr $i + 1`
+ done
+
+ echo "Virtual WAN established successfully!"
+}
+
+virtual_chain_create_interface_with_ip() {
+
+ NODE_NAME=$1
+ NODE_IP=$2
+
+ # Create a ng_eiface object for virtual node. ng_eiface
+ # object has a hook that can be connected to one of bridge
+ # links. After creating interface get its automatically
+ # generated name for further usage.
+
+ echo "Creating eiface interface for virtual node ${NODE_NAME}."
+ ngctl mkpeer eiface ether ether
+ EIFACE=`ngctl l | grep ngeth | tail -n 1| awk '{print $2}'`
+ echo "Interface ${EIFACE} is created."
+
+ # Write name of the interface to temp file. Clean-up procedure
+ # will use this name to shutdown interface.
+
+ echo "interface ${EIFACE}" >> ${TEMP_FILE}
+
+ # Move virtual interface to virtual node. Note that Interface
+ # name will not be changed at the end of this movement. Moved
+ # interface can be seen at the output of ifconfig command in
+ # jail: 'jexec jailname ifconfig'
+
+ echo "Moving ${EIFACE} to ${NODE_NAME}"
+ ifconfig ${EIFACE} vnet ${NODE_NAME}
+
+ # Make lo0 interface localhost.
+ jexec ${NODE_NAME} ifconfig lo0 localhost
+
+ # Generate a random mac address for virtual interface. First
+ # three octets can be changed by user. Last three octets are
+ # generated randomly.
+ M4=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+ M5=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+ M6=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+
+ MAC=`printf ${MAC_PREFIX}:%02x:%02x:%02x ${M4} ${M5} ${M6}`
+
+ # Set the link address (mac address) of virtual interface in
+ # virtual node to randomly generated MAC.
+ echo "Setting MAC address of ${EIFACE} to '${MAC}'"
+ jexec ${NODE_NAME} ifconfig ${EIFACE} link $MAC
+
+ # Either IPv4 or IPv6 can be used in this script. Ifconfig
+ # IP setting syntax differs slightly for two IP versions.
+ # For version 4 'inet' keyword is used whereas for version 6
+ # 'inet6' is used. Below line tries to decide which IP version
+ # is given and sets IPVER to 'inet' or 'inet6'.
+
+ IPVER=`echo ${NODE_IP} | awk -F"." '{ split($4,last,"/"); \
+ if( NF==4 && $1>0 && $1<256 && $2<256 && $3<256 && \
+ last[1]<256) print "inet"; else print "inet6"}'`
+
+ # Set IP address of virtual interface in virtual node.
+ echo "Setting IP address of ${EIFACE} to '${NODE_IP}'"
+ jexec ${NODE_NAME} ifconfig ${EIFACE} ${IPVER} ${NODE_IP}
+
+ RET_INTERFACE=${EIFACE}
+}
+
+virtual_chain_create_peer_if_necessary() {
+
+ if ! grep -q $1 ${TEMP_FILE} ; then
+
+ echo -n "Creating virtual node (jail) ${1}..."
+ jail -c vnet name=${1} host.hostname=${1} \
+ path=${JAIL_PATH} persist
+ jexec ${1} sysctl -w net.inet.ip.forwarding=1
+ jexec ${1} sysctl -w net.inet6.ip6.forwarding=1
+ echo "done"
+
+ # Write name of the jail to temp file. Clean-up
+ # procedure will use this name to remove jail.
+
+ echo "node ${1}" >> ${TEMP_FILE}
+ fi
+
+}
+
+# Stop routine.
+virtual_chain_stop() {
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo "Nothing to stop! ${TEMP_FILE}: temp file not found"
+ else
+
+ echo -n "Shutdown bridge interface.."
+ OBJECTS=`cat ${TEMP_FILE} | grep bridge | awk '{print $2}'`
+ for BRIDGE in ${OBJECTS}; do
+ ngctl shutdown ${BRIDGE}: >/dev/null 2>&1
+ done
+ echo "done"
+
+ echo -n "Shutdown all eiface interfaces..."
+ OBJECTS=`cat ${TEMP_FILE} | grep interface | awk '{print $2}'`
+ for INTERFACE in ${OBJECTS}; do
+ ngctl shutdown ${INTERFACE}: >/dev/null 2>&1
+ done
+ echo "done"
+
+ echo -n "Removing all jails..."
+ OBJECTS=`cat ${TEMP_FILE} | grep node | awk '{print $2}'`
+ for NODE in ${OBJECTS}; do
+ jail -r ${NODE}
+ done
+ echo "done"
+
+ echo "Removing tempfile ${TEMP_FILE}"
+ rm ${TEMP_FILE}
+ fi
+ echo "Virtual LAN objects removed successfully!"
+
+}
+
+virtual_chain_usage() {
+ echo "usage: $0 start [target_topology]"
+ echo " : $0 [ stop | help ]"
+}
+
+
+# Main entry point.
+
+case $# in
+ 1)
+ case $1 in
+ start)
+ echo -n "Creating default target topology:"
+ echo " ${TARGET_TOPOLOGY}"
+ virtual_chain_start
+ ;;
+ stop)
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo -n "Noting to stop! ${TEMP_FILE}:"
+ echo " temp file not found"
+ else
+ virtual_chain_stop
+ fi
+ ;;
+ help)
+ virtual_chain_usage
+ exit 1
+ ;;
+ *)
+ virtual_chain_usage
+ exit 1
+
+ esac
+ ;;
+ 2)
+ case $1 in
+ start)
+ TARGET_TOPOLOGY=$2
+ echo -n "Creating target topology:"
+ echo "${TARGET_TOPOLOGY}"
+ virtual_chain_start
+ ;;
+ *)
+ virtual_chain_usage
+ exit 1
+ esac
+ ;;
+
+ *)
+ virtual_chain_usage
+ exit 1
+esac
+
diff --git a/share/examples/netgraph/virtual.lan b/share/examples/netgraph/virtual.lan
new file mode 100644
index 000000000000..2ec47aa08b51
--- /dev/null
+++ b/share/examples/netgraph/virtual.lan
@@ -0,0 +1,358 @@
+#!/bin/sh
+#
+# Copyright (c) 2010, Yavuz Gokirmak
+#
+# All rights reserved.
+#
+# This source code may be used, modified, copied, distributed, and
+# sold, in both source and binary form provided that the above
+# copyright and these terms are retained, verbatim, as the first
+# lines of this file. Under no circumstances is the author
+# responsible for the proper functioning of the software nor does
+# the author assume any responsibility for damages incurred with
+# its use.
+#
+#
+# This script adds virtual nodes to one of the physical interfaces
+# visible on your local area network (LAN). Virtual nodes seems real
+# to external observers.
+# If traceroute is executed to one of virtual nodes, the IP
+# address of the physical interface will not be seen in the output.
+# Virtual nodes are generated via jails and network connections are
+# established using ng_bridge(4) and ng_eiface(4) node types.
+#
+# To use this script:
+#
+# 0. Make your own copy of this example script.
+#
+# 1. Edit the definition of ${ETHER_INTF} as described below
+# to define your real interface connected to the LAN. Virtual nodes
+# will placed on the same physical network as this interface.
+#
+# 2. Edit the definition of ${TARGET_TOPOLOGY} to define your virtual
+# nodes. Virtual topology definition includes node names and their
+# IP address. Target top. syntax: ( node1|ip1/24 node2|ip2/24 ... )
+# Example 1: ( n1|122.122.122.12/24, n2|122.122.122.13/24 ...)
+# Example 2: ( n1|2001:b90::14a/125, n1|2001:b90::14b/125 ...)
+#
+# 3. Run this script with "start" as the command line argument.
+#
+# 4. Stop bridging by running this script with "stop" as the
+# command line argument.
+#
+# 5. This script uses a template file in order to carry information
+# between start and stop calls.
+# In the start call, the netgraph interfaces and jails are created.
+# At the stop phase, all created objects should be removed.
+# DO NOT delete the temporary file between the start and stop phases.
+#
+# To add virtual nodes for multiple independent LANs, create multiple
+# copies of this script with different variable definitions.
+#
+# Target Topology:
+#
+#
+# +---------------+ +---------------+ +---------------+
+# | n0 (vimage) | | n1 (vimage) | | nk (vimage) |
+# | | | | | |
+# | +-----------+ | | +-----------+ | | +-----------+ |
+# | | ngeth0 | | | | ngeth1 | | | | ngethk | |
+# | |(ng_eiface)| | | |(ng_eiface)| | | |(ng_eiface)| |
+# | +--+-----+--+ | | +--+-----+--+ | | +--+-----+--+ |
+# | |ether| | | |ether| | | |ether| |
+# | +--X--+ | | +--X--+ | | +---X-+ |
+# +-----+ +--------\------+ +--------\------+ +-------/-------+
+# |upper|----\ \ip_addr \ip_addr /ip_addr
+# +-+-----+--+ \ \ \ \
+# | em0 | \ +--------+ +-+ \
+# |(ng_ether)| +-----------+ \ \ \
+# +-+-----+--+ \ \ / \
+# |lower| +---------\ \ \ / /
+# +--X--+ / O--X--O O-X---O O---X-O O--X--O O---X---O
+# \ | |link0| |link1| |link2| |link3| |linkk+2|
+# \ / +-O-----O-O-----O-O-----O-O-----O-----O-------O-+
+# +---+ | |
+# | bridge (ng_bridge) |
+# +-----------------------------------------------+
+#
+#
+
+# Give the name of ethernet interface. Virtual nodes will be seen as
+# local neighbours of this interface.
+
+ETHER_INTF="em0"
+
+# List the names of virtual nodes and their IP addresses. Use ':'
+# character to separate node name from node IP address and netmask.
+
+TARGET_TOPOLOGY="c1|10.0.2.20/24 c2|10.0.2.21/24 c3|10.0.2.22/24"
+
+# MAC manufacturer prefix. This can be modified according to needs.
+MAC_PREFIX="00:1d:92"
+
+# Temporary file is important for proper execution of script.
+TEMP_FILE="/var/tmp/.virtual.lan.tmp"
+
+# Set root directory for jails to be created.
+JAIL_PATH="/usr/jails/node"
+
+
+####################################################################
+#### Nothing below this point should need to be modified. ####
+####################################################################
+
+
+# Start/restart routine.
+virtual_lan_start() {
+
+ # Load netgraph KLD's as necessary.
+
+ for KLD in ng_ether ng_bridge ng_eiface; do
+ if ! kldstat -v | grep -qw ${KLD}; then
+ echo -n "Loading ${KLD}.ko... "
+ kldload ${KLD} || exit 1
+ echo "done"
+ fi
+ done
+
+ # Reset all interfaces and jails. If temporary file can not be found
+ # script assumes that there is no previous configuration.
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo "No previous configuration(${TEMP_FILE}) found to clean-up."
+ else
+ echo -n "Cleaning previous configuration..."
+ virtual_lan_stop
+ echo "done"
+ fi
+
+ # Create temporary file for usage. This file includes generated
+ # interface names and jail names. All bridges, interfaces and jails
+ # are written to file while created. In clean-up process written
+ # objects are cleaned (i.e. removed) from system.
+
+ if [ -e ${TEMP_FILE} ]; then
+ touch ${TEMP_FILE}
+ fi
+
+ echo -n "Verifying ethernet interface existence..."
+ # Verify ethernet interface exist.
+ if ! ngctl info ${ETHER_INTF}: >/dev/null 2>&1; then
+ echo "Error: interface ${ETHER_INTF} does not exist"
+ exit 1
+ fi
+ ifconfig ${ETHER_INTF} up || exit 1
+ echo "done"
+
+ # Get current number of bridge interfaces in the system. This number
+ # is used to create a name for new bridge.
+ BRIDGE_COUNT=`ngctl l | grep bridge | wc -l | sed -e "s/ //g"`
+ BRIDGE_NAME="bridge${BRIDGE_COUNT}"
+
+ # Create new ng_bridge(4) node and attach it to the ethernet interface.
+ # Connect ng_ether:lower hook to bridge:link0 when creating bridge and
+ # connect ng_ether:upper hook to bridge:link1 after bridge name is set.
+
+ echo "Creating bridge interface: ${BRIDGE_NAME}..."
+ ngctl mkpeer ${ETHER_INTF}: bridge lower link0 || exit 1
+ ngctl name ${ETHER_INTF}:lower ${BRIDGE_NAME} || exit 1
+ ngctl connect ${ETHER_INTF}: ${BRIDGE_NAME}: upper link1 || exit 1
+ echo "Bridge ${BRIDGE_NAME} is created and ${ETHER_INTF} is connected."
+
+ # In the above code block two hooks are connected to bridge interface,
+ # therefore LINKNUM is set to 2 indicating total number of connected
+ # hooks on the bridge interface.
+ LINKNUM=2
+
+ # Write name of the bridge to temp file. Clean-up procedure will use
+ # this name to shutdown bridge interface.
+ echo "bridge ${BRIDGE_NAME}" > ${TEMP_FILE}
+
+
+ # Attach other interfaces as well.
+ for NODE in ${TARGET_TOPOLOGY}; do
+
+ # Virtual nodes are defined in TARGET_TOPOLOGY variable. They
+ # have the form of 'nodeName|IPaddr'. Below two lines split
+ # node definition to get node name and node IP.
+
+ NODE_NAME=`echo ${NODE} | awk -F"|" '{print $1}'`
+ NODE_IP=`echo ${NODE} | awk -F"|" '{print $2}'`
+
+ # Create virtual node (jail) with given name and using
+ # JAIL_PATH as root directory for jail.
+
+ echo -n "Creating virtual node (jail) ${NODE_NAME}..."
+ jail -c vnet name=${NODE_NAME} host.hostname=${NODE_NAME} \
+ path=${JAIL_PATH} persist
+ echo "done"
+
+ # Write name of the jail to temp file. Clean-up procedure will
+ # use this name to remove jail.
+
+ echo "node ${NODE_NAME}" >> ${TEMP_FILE}
+
+ # Create a ng_eiface object for virtual node. ng_eiface
+ # object has a hook that can be connected to one of bridge
+ # links. After creating interface get its automatically
+ # generated name for further usage.
+
+ echo "Creating eiface interface for virtual node ${NODE_NAME}."
+ ngctl mkpeer eiface ether ether
+ EIFACE=`ngctl l | grep ngeth | tail -n 1| awk '{print $2}'`
+ echo "Interface ${EIFACE} is created."
+
+ # Write name of the interface to temp file. Clean-up procedure
+ # will use this name to shutdown interface.
+
+ echo "interface ${EIFACE}" >> ${TEMP_FILE}
+
+ # Move virtual interface to virtual node. Note that Interface
+ # name will not be changed at the end of this movement. Moved
+ # interface can be seen at the output of ifconfig command in
+ # jail: 'jexec jailname ifconfig'
+
+ echo "Moving ${EIFACE} to ${NODE_NAME}"
+ ifconfig ${EIFACE} vnet ${NODE_NAME}
+
+ # Make lo0 interface localhost.
+ jexec ${NODE_NAME} ifconfig lo0 localhost
+
+ # Generate a random mac address for virtual interface. First
+ # three octets can be changed by user. Last three octets are
+ # generated randomly.
+ M4=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+ M5=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+ M6=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+
+ MAC=`printf ${MAC_PREFIX}:%02x:%02x:%02x ${M4} ${M5} ${M6}`
+
+ # Set the link address (mac address) of virtual interface in
+ # virtual node to randomly generated MAC.
+ echo "Setting MAC address of ${EIFACE} to '${MAC}'"
+ jexec ${NODE_NAME} ifconfig ${EIFACE} link $MAC
+
+ # Either IPv4 or IPv6 can be used in this script. Ifconfig
+ # IP setting syntax differs slightly for two IP versions.
+ # For version 4 'inet' keyword is used whereas for version 6
+ # 'inet6' is used. Below line tries to decide which IP version
+ # is given and sets IPVER to 'inet' or 'inet6'.
+
+ IPVER=`echo ${NODE_IP} | awk -F"." '{ split($4,last,"/"); \
+ if( NF==4 && $1>0 && $1<256 && $2<256 && $3<256 && \
+ last[1]<256) print "inet"; else print "inet6"}'`
+
+ # Set IP address of virtual interface in virtual node.
+ echo "Setting IP address of ${EIFACE} to '${NODE_IP}'"
+ jexec ${NODE_NAME} ifconfig ${EIFACE} ${IPVER} ${NODE_IP}
+
+ # Connect virtual interface to bridge interface. Syntax is :
+ # ngctl connect INTERFACE: BRIDGE: INTERFACE_HOOK EMPTY_LINK.
+ # Interface has one hook named 'ether' and below line connects
+ # ether hook to bridge's first unconnected link.
+
+ echo -n "Connecting ${EIFACE}:ether to ${BRIDGE_NAME}:link${LINKNUM}..."
+ ngctl connect ${EIFACE}: ${BRIDGE_NAME}: ether link${LINKNUM} \
+ || exit 1
+ echo "done"
+
+ # Now, bridge has one more connected link thus link count is
+ # incremented.
+ LINKNUM=`expr ${LINKNUM} + 1`
+ done
+ echo "Virtual LAN established successfully!"
+
+}
+
+# Stop routine.
+virtual_lan_stop() {
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo "Nothing to stop! ${TEMP_FILE}: temp file not found"
+ else
+
+ echo -n "Shutdown bridge interface.."
+ OBJECTS=`cat ${TEMP_FILE} | grep bridge | awk '{print $2}'`
+ for BRIDGE in ${OBJECTS}; do
+ ngctl shutdown ${BRIDGE}: >/dev/null 2>&1
+ done
+ echo "done"
+
+ echo -n "Shutdown all eiface interfaces..."
+ OBJECTS=`cat ${TEMP_FILE} | grep interface | awk '{print $2}'`
+ for INTERFACE in ${OBJECTS}; do
+ ngctl shutdown ${INTERFACE}: >/dev/null 2>&1
+ done
+ echo "done"
+
+ echo -n "Removing all jails..."
+ OBJECTS=`cat ${TEMP_FILE} | grep node | awk '{print $2}'`
+ for NODE in ${OBJECTS}; do
+ jail -r ${NODE}
+ done
+ echo "done"
+
+ echo "Removing tempfile ${TEMP_FILE}"
+ rm ${TEMP_FILE}
+ fi
+ echo "Virtual LAN objects removed successfully!"
+
+}
+
+virtual_lan_usage() {
+ echo "usage: $0 start [target_topology]"
+ echo " : $0 [ stop | help ]"
+}
+
+
+# Main entry point.
+
+case $# in
+ 1)
+ case $1 in
+ start)
+ echo -n "Creating default target topology:"
+ echo " ${TARGET_TOPOLOGY}"
+ virtual_lan_start
+ ;;
+ stop)
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo -n "Noting to stop! ${TEMP_FILE}:"
+ echo " temp file not found"
+ else
+ virtual_lan_stop
+ fi
+ ;;
+ help)
+ virtual_lan_usage
+ exit 1
+ ;;
+ *)
+ virtual_lan_usage
+ exit 1
+
+ esac
+ ;;
+ 2)
+ case $1 in
+ start)
+ TARGET_TOPOLOGY=$2
+ echo -n "Creating target topology:"
+ echo "${TARGET_TOPOLOGY}"
+ virtual_lan_start
+ ;;
+ *)
+ virtual_lan_usage
+ exit 1
+ esac
+ ;;
+
+ *)
+ virtual_lan_usage
+ exit 1
+esac
+
diff --git a/share/examples/perfmon/Makefile b/share/examples/perfmon/Makefile
new file mode 100644
index 000000000000..a687980e7808
--- /dev/null
+++ b/share/examples/perfmon/Makefile
@@ -0,0 +1,9 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/${PROG}
+PROG= perfmon
+MAN=
+
+install:
+
+.include <bsd.prog.mk>
diff --git a/share/examples/perfmon/README b/share/examples/perfmon/README
new file mode 100644
index 000000000000..25452813f3db
--- /dev/null
+++ b/share/examples/perfmon/README
@@ -0,0 +1,23 @@
+`perfmon' is a sample program to access the performance-monitoring
+counters on Pentium and Pentium Pro CPUs. See perfmon(4) for a
+description of this facility.
+
+The program takes the following options:
+
+ -u count events in user mode
+ -o count events in kernel mode
+ (these two can be combined)
+
+ -e count events, not duration
+ -l n run `n' loops (default 50)
+ -s n sleep `n' seconds between loop iterations (default 0)
+
+The following options are not implemented on Pentium CPUs:
+
+ -m n use count mask `n'
+ -i invert sense of count mask comparison
+ -U n use unit mask `n'
+
+There is one mandatory argument, which is the event number to be
+monitored, defined in <machine/perfmon.h>. All numbers can be
+specified in any format acceptable to strtol(3).
diff --git a/share/examples/perfmon/perfmon.c b/share/examples/perfmon/perfmon.c
new file mode 100644
index 000000000000..1b7afad9d69e
--- /dev/null
+++ b/share/examples/perfmon/perfmon.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright 1996 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <machine/cpu.h>
+#include <machine/perfmon.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <errno.h>
+
+static int getnum(const char *, int, int);
+static void usage(const char *) __dead2;
+
+int
+main(int argc, char **argv)
+{
+ int c, fd, num;
+ int loops, i, sleeptime;
+ char *cmd;
+ struct pmc pmc;
+ struct pmc_tstamp then, now;
+ struct pmc_data value;
+ quad_t *buf;
+ double total;
+
+ pmc.pmc_num = 0;
+ pmc.pmc_event = 0;
+ pmc.pmc_unit = 0;
+ pmc.pmc_flags = 0;
+ pmc.pmc_mask = 0;
+ cmd = NULL;
+ loops = 50;
+ sleeptime = 0;
+
+ while ((c = getopt(argc, argv, "s:l:uoeiU:m:c:")) != -1) {
+ switch(c) {
+ case 'u':
+ pmc.pmc_flags |= PMCF_USR;
+ break;
+ case 'o':
+ pmc.pmc_flags |= PMCF_OS;
+ break;
+ case 'e':
+ pmc.pmc_flags |= PMCF_E;
+ break;
+ case 'i':
+ pmc.pmc_flags |= PMCF_INV;
+ break;
+ case 'U':
+ pmc.pmc_unit = getnum(optarg, 0, 256);
+ break;
+ case 'm':
+ pmc.pmc_mask = getnum(optarg, 0, 256);
+ break;
+ case 'l':
+ loops = getnum(optarg, 1, INT_MAX - 1);
+ break;
+ case 's':
+ sleeptime = getnum(optarg, 0, INT_MAX - 1);
+ break;
+ case 'c':
+ cmd = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if (argc - optind != 1)
+ usage(argv[0]);
+
+ pmc.pmc_event = getnum(argv[optind], 0, 255);
+
+ buf = malloc((loops + 1) * sizeof *buf);
+ if (!buf)
+ err(1, "malloc(%lu)", (unsigned long)(loops +1) * sizeof *buf);
+
+ fd = open(_PATH_PERFMON, O_RDWR, 0);
+ if (fd < 0)
+ err(1, "open: " _PATH_PERFMON);
+
+ if (ioctl(fd, PMIOSETUP, &pmc) < 0)
+ err(1, "ioctl(PMIOSETUP)");
+
+ if (ioctl(fd, PMIOTSTAMP, &then) < 0)
+ err(1, "ioctl(PMIOTSTAMP)");
+
+ num = 0;
+ if (ioctl(fd, PMIOSTART, &num) < 0)
+ err(1, "ioctl(PMIOSTART)");
+
+ value.pmcd_num = 0;
+ for (i = 0; i < loops; i++) {
+ if (ioctl(fd, PMIOSTOP, &num) < 0)
+ err(1, "ioctl(PMIOSTOP)");
+ if (ioctl(fd, PMIOREAD, &value) < 0)
+ err(1, "ioctl(PMIOREAD)");
+ buf[i] = value.pmcd_value;
+ if (ioctl(fd, PMIORESET, &value.pmcd_num) < 0)
+ err(1, "ioctl(PMIORESET)");
+ if (ioctl(fd, PMIOSTART, &num) < 0)
+ err(1, "ioctl(PMIOSTART)");
+ if (sleeptime)
+ sleep(sleeptime);
+ if (cmd)
+ system(cmd);
+ }
+
+ if (ioctl(fd, PMIOSTOP, &num) < 0)
+ err(1, "ioctl(PMIOSTOP)");
+ if (ioctl(fd, PMIOREAD, &value) < 0)
+ err(1, "ioctl(PMIOREAD)");
+ buf[i] = value.pmcd_value;
+ if (ioctl(fd, PMIOTSTAMP, &now) < 0)
+ err(1, "ioctl(PMIOTSTAMP)");
+
+ total = 0;
+ for (i = 1; i <= loops; i++) {
+ printf("%d: %qd\n", i, buf[i]);
+ total += buf[i];
+ }
+ printf("total: %f\nmean: %f\n", total, total / loops);
+
+ printf("clocks (at %d-MHz): %qd\n", now.pmct_rate,
+ now.pmct_value - then.pmct_value);
+
+ return 0;
+}
+
+static int
+getnum(const char *buf, int min, int max)
+{
+ char *ep;
+ long l;
+
+ errno = 0;
+ l = strtol(buf, &ep, 0);
+ if (*buf && !*ep && !errno) {
+ if (l < min || l > max) {
+ errx(1, "%s: must be between %d and %d",
+ buf, min, max);
+ }
+ return (int)l;
+ }
+
+ errx(1, "%s: parameter must be an integer", buf);
+}
+
+static void
+usage(const char *pname)
+{
+ fprintf(stderr,
+ "usage: %s [-eiou] [-c command] [-l nloops] [-m mask] [-s sleeptime]\n"
+ " [-U unit] counter\n",
+ pname);
+ exit(1);
+}
diff --git a/share/examples/pf/Makefile b/share/examples/pf/Makefile
new file mode 100644
index 000000000000..4ea4f9c79bb8
--- /dev/null
+++ b/share/examples/pf/Makefile
@@ -0,0 +1,10 @@
+
+PACKAGE=examples
+FILES= faq-example1 faq-example2 faq-example3 \
+ ackpri queue1 queue2 queue3 queue4 \
+ pf.conf \
+ spamd
+
+FILESDIR= ${SHAREDIR}/examples/pf
+
+.include <bsd.prog.mk>
diff --git a/share/examples/pf/Makefile.depend b/share/examples/pf/Makefile.depend
new file mode 100644
index 000000000000..11aba52f82cf
--- /dev/null
+++ b/share/examples/pf/Makefile.depend
@@ -0,0 +1,10 @@
+# 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/share/examples/pf/ackpri b/share/examples/pf/ackpri
new file mode 100644
index 000000000000..2dd42b9bb3b1
--- /dev/null
+++ b/share/examples/pf/ackpri
@@ -0,0 +1,30 @@
+# $OpenBSD: ackpri,v 1.3 2006/10/07 04:48:01 mcbride Exp $
+
+# Use a simple priority queue to prioritize empty (no payload) TCP ACKs,
+# which dramatically improves throughput on (asymmetric) links when the
+# reverse direction is saturated. The empty ACKs use an insignificant
+# part of the bandwidth, but if they get delayed, downloads suffer
+# badly, so prioritize them.
+
+# Example: 512/128 kbps ADSL. Download is 50 kB/s. When a concurrent
+# upload saturates the uplink, download drops to 7 kB/s. With the
+# priority queue below, download drops only to 48 kB/s.
+
+# Replace lo0 with your real external interface
+
+ext_if="lo0"
+
+# For a 512/128 kbps ADSL with PPPoE link, using "bandwidth 100Kb"
+# is optimal. Some experimentation might be needed to find the best
+# value. If it's set too high, the priority queue is not effective, and
+# if it's set too low, the available bandwidth is not fully used.
+# A good starting point would be real_uplink_bandwidth * 90 / 100.
+
+altq on $ext_if priq bandwidth 100Kb queue { q_pri, q_def }
+queue q_pri priority 7
+queue q_def priority 1 priq(default)
+
+pass out on $ext_if proto tcp from $ext_if to any queue (q_def, q_pri)
+
+pass in on $ext_if proto tcp from any to $ext_if queue (q_def, q_pri)
+
diff --git a/share/examples/pf/faq-example1 b/share/examples/pf/faq-example1
new file mode 100644
index 000000000000..9045cd86bc59
--- /dev/null
+++ b/share/examples/pf/faq-example1
@@ -0,0 +1,50 @@
+# $OpenBSD: faq-example1,v 1.5 2006/10/07 04:48:01 mcbride Exp $
+
+#
+# Firewall for Home or Small Office
+# http://www.openbsd.org/faq/pf/example1.html
+#
+
+
+# macros
+ext_if="fxp0"
+int_if="xl0"
+
+tcp_services="{ 22, 113 }"
+icmp_types="echoreq"
+
+comp3="192.168.0.3"
+
+# options
+set block-policy return
+set loginterface $ext_if
+
+set skip on lo
+
+# scrub
+scrub in
+
+# nat/rdr
+nat on $ext_if inet from !($ext_if) -> ($ext_if:0)
+nat-anchor "ftp-proxy/*"
+rdr-anchor "ftp-proxy/*"
+
+rdr pass on $int_if proto tcp to port ftp -> 127.0.0.1 port 8021
+rdr on $ext_if proto tcp from any to any port 80 -> $comp3
+
+# filter rules
+block in
+
+pass out
+
+anchor "ftp-proxy/*"
+antispoof quick for { lo $int_if }
+
+pass in on $ext_if inet proto tcp from any to ($ext_if) port $tcp_services
+
+pass in on $ext_if inet proto tcp from any to $comp3 port 80 \
+ synproxy state
+
+pass in inet proto icmp all icmp-type $icmp_types
+
+pass quick on $int_if no state
diff --git a/share/examples/pf/faq-example2 b/share/examples/pf/faq-example2
new file mode 100644
index 000000000000..e3dea440e83a
--- /dev/null
+++ b/share/examples/pf/faq-example2
@@ -0,0 +1,88 @@
+# $OpenBSD: faq-example2,v 1.4 2006/10/07 04:48:01 mcbride Exp $
+
+#
+# Small, Home Network
+# http://www.openbsd.org/faq/pf/queueing.html#example1
+#
+
+
+# enable queueing on the external interface to control traffic going to
+# the Internet. use the priq scheduler to control only priorities. set
+# the bandwidth to 610Kbps to get the best performance out of the TCP
+# ACK queue.
+
+altq on fxp0 priq bandwidth 610Kb queue { std_out, ssh_im_out, dns_out, \
+ tcp_ack_out }
+
+# define the parameters for the child queues.
+# std_out - the standard queue. any filter rule below that does not
+# explicitly specify a queue will have its traffic added
+# to this queue.
+# ssh_im_out - interactive SSH and various instant message traffic.
+# dns_out - DNS queries.
+# tcp_ack_out - TCP ACK packets with no data payload.
+
+queue std_out priq(default)
+queue ssh_im_out priority 4 priq(red)
+queue dns_out priority 5
+queue tcp_ack_out priority 6
+
+# enable queueing on the internal interface to control traffic coming in
+# from the Internet. use the cbq scheduler to control bandwidth. max
+# bandwidth is 2Mbps.
+
+altq on dc0 cbq bandwidth 2Mb queue { std_in, ssh_im_in, dns_in, bob_in }
+
+# define the parameters for the child queues.
+# std_in - the standard queue. any filter rule below that does not
+# explicitly specify a queue will have its traffic added
+# to this queue.
+# ssh_im_in - interactive SSH and various instant message traffic.
+# dns_in - DNS replies.
+# bob_in - bandwidth reserved for Bob's workstation. allow him to
+# borrow.
+
+queue std_in bandwidth 1.6Mb cbq(default)
+queue ssh_im_in bandwidth 200Kb priority 4
+queue dns_in bandwidth 120Kb priority 5
+queue bob_in bandwidth 80Kb cbq(borrow)
+
+
+# ... in the filtering section of pf.conf ...
+
+alice = "192.168.0.2"
+bob = "192.168.0.3"
+charlie = "192.168.0.4"
+local_net = "192.168.0.0/24"
+ssh_ports = "{ 22 2022 }"
+im_ports = "{ 1863 5190 5222 }"
+
+# filter rules for fxp0 inbound
+block in on fxp0 all
+
+# filter rules for fxp0 outbound
+block out on fxp0 all
+pass out on fxp0 inet proto tcp from (fxp0) to any \
+ queue(std_out, tcp_ack_out)
+pass out on fxp0 inet proto { udp icmp } from (fxp0) to any
+pass out on fxp0 inet proto { tcp udp } from (fxp0) to any port domain \
+ queue dns_out
+pass out on fxp0 inet proto tcp from (fxp0) to any port $ssh_ports \
+ queue(std_out, ssh_im_out)
+pass out on fxp0 inet proto tcp from (fxp0) to any port $im_ports \
+ queue(ssh_im_out, tcp_ack_out)
+
+# filter rules for dc0 inbound
+block in on dc0 all
+pass in on dc0 from $local_net
+
+# filter rules for dc0 outbound
+block out on dc0 all
+pass out on dc0 from any to $local_net
+pass out on dc0 proto { tcp udp } from any port domain to $local_net \
+ queue dns_in
+pass out on dc0 proto tcp from any port $ssh_ports to $local_net \
+ queue(std_in, ssh_im_in)
+pass out on dc0 proto tcp from any port $im_ports to $local_net \
+ queue ssh_im_in
+pass out on dc0 from any to $bob queue bob_in
diff --git a/share/examples/pf/faq-example3 b/share/examples/pf/faq-example3
new file mode 100644
index 000000000000..b4793110842d
--- /dev/null
+++ b/share/examples/pf/faq-example3
@@ -0,0 +1,116 @@
+# $OpenBSD: faq-example3,v 1.4 2006/10/07 04:48:01 mcbride Exp $
+
+#
+# Company Network
+# http://www.openbsd.org/faq/pf/queueing.html#example2
+#
+
+
+# enable queueing on the external interface to queue packets going out
+# to the Internet. use the cbq scheduler so that the bandwidth use of
+# each queue can be controlled. the max outgoing bandwidth is 1.5Mbps.
+
+altq on fxp0 cbq bandwidth 1.5Mb queue { std_ext, www_ext, boss_ext }
+
+# define the parameters for the child queues.
+# std_ext - the standard queue. also the default queue for
+# outgoing traffic on fxp0.
+# www_ext - container queue for WWW server queues. limit to
+# 500Kbps.
+# www_ext_http - http traffic from the WWW server; higher priority.
+# www_ext_misc - all non-http traffic from the WWW server.
+# boss_ext - traffic coming from the boss's computer.
+
+queue std_ext bandwidth 500Kb cbq(default borrow)
+queue www_ext bandwidth 500Kb { www_ext_http, www_ext_misc }
+ queue www_ext_http bandwidth 50% priority 3 cbq(red borrow)
+ queue www_ext_misc bandwidth 50% priority 1 cbq(borrow)
+queue boss_ext bandwidth 500Kb priority 3 cbq(borrow)
+
+# enable queueing on the internal interface to control traffic coming
+# from the Internet or the DMZ. use the cbq scheduler to control the
+# bandwidth of each queue. bandwidth on this interface is set to the
+# maximum. traffic coming from the DMZ will be able to use all of this
+# bandwidth while traffic coming from the Internet will be limited to
+# 1.0Mbps (because 0.5Mbps (500Kbps) is being allocated to fxp1).
+
+altq on dc0 cbq bandwidth 100% queue { net_int, www_int }
+
+# define the parameters for the child queues.
+# net_int - container queue for traffic from the Internet. bandwidth
+# is 1.0Mbps.
+# std_int - the standard queue. also the default queue for outgoing
+# traffic on dc0.
+# it_int - traffic to the IT Dept network; reserve them 500Kbps.
+# boss_int - traffic to the boss's PC; assign a higher priority.
+# www_int - traffic from the WWW server in the DMZ; full speed.
+
+queue net_int bandwidth 1.0Mb { std_int, it_int, boss_int }
+ queue std_int bandwidth 250Kb cbq(default borrow)
+ queue it_int bandwidth 500Kb cbq(borrow)
+ queue boss_int bandwidth 250Kb priority 3 cbq(borrow)
+queue www_int bandwidth 99Mb cbq(red borrow)
+
+# enable queueing on the DMZ interface to control traffic destined for
+# the WWW server. cbq will be used on this interface since detailed
+# control of bandwidth is necessary. bandwidth on this interface is set
+# to the maximum. traffic from the internal network will be able to use
+# all of this bandwidth while traffic from the Internet will be limited
+# to 500Kbps.
+
+altq on fxp1 cbq bandwidth 100% queue { internal_dmz, net_dmz }
+
+# define the parameters for the child queues.
+# internal_dmz - traffic from the internal network.
+# net_dmz - container queue for traffic from the Internet.
+# net_dmz_http - http traffic; higher priority.
+# net_dmz_misc - all non-http traffic. this is also the default queue.
+
+queue internal_dmz bandwidth 99Mb cbq(borrow)
+queue net_dmz bandwidth 500Kb { net_dmz_http, net_dmz_misc }
+ queue net_dmz_http bandwidth 50% priority 3 cbq(red borrow)
+ queue net_dmz_misc bandwidth 50% priority 1 cbq(default borrow)
+
+
+# ... in the filtering section of pf.conf ...
+
+main_net = "192.168.0.0/24"
+it_net = "192.168.1.0/24"
+int_nets = "{ 192.168.0.0/24, 192.168.1.0/24 }"
+dmz_net = "10.0.0.0/24"
+
+boss = "192.168.0.200"
+wwwserv = "10.0.0.100"
+
+# default deny
+block on { fxp0, fxp1, dc0 } all
+
+# filter rules for fxp0 inbound
+pass in on fxp0 proto tcp from any to $wwwserv port { 21, \
+ > 49151 } queue www_ext_misc
+pass in on fxp0 proto tcp from any to $wwwserv port 80 \
+ queue www_ext_http
+
+# filter rules for fxp0 outbound
+pass out on fxp0 from $int_nets to any
+pass out on fxp0 from $boss to any queue boss_ext
+
+# filter rules for dc0 inbound
+pass in on dc0 from $int_nets to any
+pass in on dc0 from $it_net to any queue it_int
+pass in on dc0 from $boss to any queue boss_int
+pass in on dc0 proto tcp from $int_nets to $wwwserv port { 21, 80, \
+ > 49151 } queue www_int
+
+# filter rules for dc0 outbound
+pass out on dc0 from dc0 to $int_nets
+
+# filter rules for fxp1 inbound
+pass in on fxp1 proto { tcp, udp } from $wwwserv to any port 53
+
+# filter rules for fxp1 outbound
+pass out on fxp1 proto tcp from any to $wwwserv port { 21, \
+ > 49151 } queue net_dmz_misc
+pass out on fxp1 proto tcp from any to $wwwserv port 80 queue net_dmz_http
+pass out on fxp1 proto tcp from $int_nets to $wwwserv port { 80, \
+ 21, > 49151 } queue internal_dmz
diff --git a/share/examples/pf/pf.conf b/share/examples/pf/pf.conf
new file mode 100644
index 000000000000..24b92fd9411c
--- /dev/null
+++ b/share/examples/pf/pf.conf
@@ -0,0 +1,34 @@
+# $OpenBSD: pf.conf,v 1.34 2007/02/24 19:30:59 millert Exp $
+#
+# See pf.conf(5) and /usr/share/examples/pf for syntax and examples.
+# Remember to set gateway_enable="YES" and/or ipv6_gateway_enable="YES"
+# in /etc/rc.conf if packets are to be forwarded between interfaces.
+
+#ext_if="ext0"
+#int_if="int0"
+
+#table <spamd-white> persist
+
+#set skip on lo
+
+#scrub in
+
+#nat-anchor "ftp-proxy/*"
+#rdr-anchor "ftp-proxy/*"
+#nat on $ext_if inet from !($ext_if) -> ($ext_if:0)
+#rdr pass on $int_if proto tcp to port ftp -> 127.0.0.1 port 8021
+#no rdr on $ext_if proto tcp from <spamd-white> to any port smtp
+#rdr pass on $ext_if proto tcp from any to any port smtp \
+# -> 127.0.0.1 port spamd
+
+#anchor "ftp-proxy/*"
+#block in
+#pass out
+
+#pass quick on $int_if no state
+#antispoof quick for { lo $int_if }
+
+#pass in on $ext_if proto tcp to ($ext_if) port ssh
+#pass in log on $ext_if proto tcp to ($ext_if) port smtp
+#pass out log on $ext_if proto tcp from ($ext_if) to port smtp
+#pass in on $ext_if inet proto icmp from any to ($ext_if) icmp-type { unreach, redir, timex }
diff --git a/share/examples/pf/queue1 b/share/examples/pf/queue1
new file mode 100644
index 000000000000..38824f38ee33
--- /dev/null
+++ b/share/examples/pf/queue1
@@ -0,0 +1,20 @@
+# $OpenBSD: queue1,v 1.4 2006/10/07 04:48:01 mcbride Exp $
+
+ext_if = "dc0"
+
+altq on $ext_if cbq bandwidth 10Mb \
+ queue { deflt, http, ssh, mail, rsets }
+queue deflt bandwidth 10% priority 0 cbq(default ecn)
+queue http bandwidth 1.5Mb priority 3 { http_vhosts, http_cust1 }
+queue http_vhosts bandwidth 40% cbq(borrow red)
+queue http_cust1 bandwidth 0.5Mb
+queue mail bandwidth 10% priority 1
+queue ssh bandwidth 100Kb priority 7 cbq(borrow)
+queue rsets bandwidth 7500b priority 0 cbq(red)
+
+block return in on $ext_if inet all queue rsets
+pass in on $ext_if inet proto tcp from any to any port 80 queue http
+pass out on $ext_if inet proto tcp from any to any port 22 queue ssh
+pass in on $ext_if inet proto tcp from any to any port 22 queue ssh
+pass out on $ext_if inet proto tcp from any to any port 25 queue mail
+pass out on $ext_if inet all
diff --git a/share/examples/pf/queue2 b/share/examples/pf/queue2
new file mode 100644
index 000000000000..1968d8f3e8a3
--- /dev/null
+++ b/share/examples/pf/queue2
@@ -0,0 +1,28 @@
+# $OpenBSD: queue2,v 1.4 2006/10/07 04:48:01 mcbride Exp $
+# advanced queue example.
+# give interactive ssh traffic priority over ssh bulk transfers (scp, sftp)
+
+ext_if="dc0"
+developerhosts="192.168.2.0/24"
+employeehosts="192.168.0.0/23"
+
+altq on $ext_if cbq bandwidth 5Mb queue { std, http, mail, ssh }
+
+queue std bandwidth 10% cbq(default)
+queue http bandwidth 60% priority 2 cbq(borrow red) { employees, developers }
+queue developers bandwidth 75% cbq(borrow)
+queue employees bandwidth 15%
+queue mail bandwidth 10% priority 0 cbq(borrow ecn)
+queue ssh bandwidth 20% cbq(borrow) { ssh_interactive, ssh_bulk }
+queue ssh_interactive bandwidth 25% priority 7
+queue ssh_bulk bandwidth 75% priority 0
+
+block return out on $ext_if inet all queue std
+pass out on $ext_if inet proto tcp from $developerhosts to any port 80 \
+ queue developers
+pass out on $ext_if inet proto tcp from $employeehosts to any port 80 \
+ queue employees
+pass out on $ext_if inet proto tcp from any to any port 22 \
+ queue(ssh_bulk, ssh_interactive)
+pass out on $ext_if inet proto tcp from any to any port 25 \
+ queue mail
diff --git a/share/examples/pf/queue3 b/share/examples/pf/queue3
new file mode 100644
index 000000000000..b33e7b8f2047
--- /dev/null
+++ b/share/examples/pf/queue3
@@ -0,0 +1,15 @@
+# $OpenBSD: queue3,v 1.3 2006/10/07 04:48:01 mcbride Exp $
+# simple PRIQ example
+
+ext_if="lo0"
+
+altq on $ext_if priq bandwidth 10Mb queue { pri-low pri-med pri-high }
+queue pri-low priority 0
+queue pri-med priority 1 priq(default)
+queue pri-high priority 2
+
+pass out on $ext_if proto tcp from any to any port 22 \
+ queue(pri-med, pri-high)
+pass out on $ext_if proto tcp from any to any port 80 queue pri-med
+pass in on $ext_if proto tcp from any to any port 80 queue pri-low
+
diff --git a/share/examples/pf/queue4 b/share/examples/pf/queue4
new file mode 100644
index 000000000000..e42299cff37e
--- /dev/null
+++ b/share/examples/pf/queue4
@@ -0,0 +1,19 @@
+# $OpenBSD: queue4,v 1.2 2003/08/22 21:50:34 david Exp $
+#
+# Hierarchical queueing for a university.
+# Three faculties; engineering, law and art are defined.
+# Departments under the engineering faculty are defined as child queues.
+# The total bandwidth for engineering faculty is shared between three
+# departments. CS department gets the half of the bandwidth, EE and IE
+# departments get the thirty percent and twenty percent of bandwidth
+# respectively. These sibling departments can use more than their linkshare
+# whenever there is no backlogged sibling queue but when a queue gets
+# backlogged, it is guaranteed that the queue gets its linkshare.
+
+altq on dc0 bandwidth 16Mb hfsc queue { eng law art }
+queue eng bandwidth 10Mb { cs ee ie }
+queue cs hfsc( default linkshare 50% )
+queue ee hfsc( linkshare 30% )
+queue ie hfsc( linkshare 20% )
+queue law bandwidth 3Mb
+queue art bandwidth 3Mb
diff --git a/share/examples/pf/spamd b/share/examples/pf/spamd
new file mode 100644
index 000000000000..31b24adc3f55
--- /dev/null
+++ b/share/examples/pf/spamd
@@ -0,0 +1,7 @@
+# $OpenBSD: spamd,v 1.2 2005/08/06 19:52:37 jmc Exp $
+
+# spamd-setup puts addresses to be redirected into table <spamd>.
+
+table <spamd> persist
+no rdr on { lo0, lo1 } from any to any
+rdr inet proto tcp from <spamd> to any port smtp -> 127.0.0.1 port spamd
diff --git a/share/examples/ppi/Makefile b/share/examples/ppi/Makefile
new file mode 100644
index 000000000000..4a4d944ca50e
--- /dev/null
+++ b/share/examples/ppi/Makefile
@@ -0,0 +1,9 @@
+# Makefile to build LCD control software for ppi(4) interface.
+#
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/ppi
+PROG= ppilcd
+MAN=
+
+.include <bsd.prog.mk>
diff --git a/share/examples/ppi/ppilcd.c b/share/examples/ppi/ppilcd.c
new file mode 100644
index 000000000000..2b3d1c4ea522
--- /dev/null
+++ b/share/examples/ppi/ppilcd.c
@@ -0,0 +1,436 @@
+/*
+ * Control LCD module hung off parallel port using the
+ * ppi 'geek port' interface.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <err.h>
+#include <sysexits.h>
+
+#include <dev/ppbus/ppbconf.h>
+#include <dev/ppbus/ppi.h>
+
+#define debug(lev, fmt, args...) if (debuglevel >= lev) fprintf(stderr, fmt "\n" , ## args);
+
+static void usage(void);
+static char *progname;
+
+#define DEFAULT_DEVICE "/dev/ppi0"
+
+/* Driver functions */
+static void hd44780_prepare(char *devname, char *options);
+static void hd44780_finish(void);
+static void hd44780_command(int cmd);
+static void hd44780_putc(int c);
+
+/*
+ * Commands
+ * Note that unrecognised command escapes are passed through with
+ * the command value set to the ASCII value of the escaped character.
+ */
+#define CMD_RESET 0
+#define CMD_BKSP 1
+#define CMD_CLR 2
+#define CMD_NL 3
+#define CMD_CR 4
+#define CMD_HOME 5
+
+#define MAX_DRVOPT 10 /* maximum driver-specific options */
+
+struct lcd_driver
+{
+ char *l_code;
+ char *l_name;
+ char *l_options[MAX_DRVOPT];
+ void (* l_prepare)(char *name, char *options);
+ void (* l_finish)(void);
+ void (* l_command)(int cmd);
+ void (* l_putc)(int c);
+};
+
+static struct lcd_driver lcd_drivertab[] = {
+ {
+ "hd44780",
+ "Hitachi HD44780 and compatibles",
+ {
+ "Reset options:",
+ " 1 1-line display (default 2)",
+ " B Cursor blink enable",
+ " C Cursor enable",
+ " F Large font select",
+ NULL
+ },
+ hd44780_prepare,
+ hd44780_finish,
+ hd44780_command,
+ hd44780_putc
+ },
+ {
+ NULL,
+ NULL,
+ {
+ NULL
+ },
+ NULL,
+ NULL
+ }
+};
+
+static void do_char(struct lcd_driver *driver, char ch);
+
+int debuglevel = 0;
+int vflag = 0;
+
+int
+main(int argc, char *argv[])
+{
+ extern char *optarg;
+ extern int optind;
+ struct lcd_driver *driver = &lcd_drivertab[0];
+ char *drivertype, *cp;
+ char *devname = DEFAULT_DEVICE;
+ char *drvopts = NULL;
+ int ch, i;
+
+ if ((progname = strrchr(argv[0], '/'))) {
+ progname++;
+ } else {
+ progname = argv[0];
+ }
+
+ drivertype = getenv("LCD_TYPE");
+
+ while ((ch = getopt(argc, argv, "Dd:f:o:v")) != -1) {
+ switch(ch) {
+ case 'D':
+ debuglevel++;
+ break;
+ case 'd':
+ drivertype = optarg;
+ break;
+ case 'f':
+ devname = optarg;
+ break;
+ case 'o':
+ drvopts = optarg;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* If an LCD type was specified, look it up */
+ if (drivertype != NULL) {
+ driver = NULL;
+ for (i = 0; lcd_drivertab[i].l_code != NULL; i++) {
+ if (!strcmp(drivertype, lcd_drivertab[i].l_code)) {
+ driver = &lcd_drivertab[i];
+ break;
+ }
+ }
+ if (driver == NULL) {
+ warnx("LCD driver '%s' not known", drivertype);
+ usage();
+ }
+ }
+ debug(1, "Driver selected for %s", driver->l_name);
+ driver->l_prepare(devname, drvopts);
+ atexit(driver->l_finish);
+
+ if (argc > 0) {
+ debug(2, "reading input from %d argument%s", argc, (argc > 1) ? "s" : "");
+ for (i = 0; i < argc; i++)
+ for (cp = argv[i]; *cp; cp++)
+ do_char(driver, *cp);
+ } else {
+ debug(2, "reading input from stdin");
+ setvbuf(stdin, NULL, _IONBF, 0);
+ while ((ch = fgetc(stdin)) != EOF)
+ do_char(driver, (char)ch);
+ }
+ exit(EX_OK);
+}
+
+static void
+usage(void)
+{
+ int i, j;
+
+ fprintf(stderr, "usage: %s [-v] [-d drivername] [-f device] [-o options] [args...]\n", progname);
+ fprintf(stderr, " -D Increase debugging\n");
+ fprintf(stderr, " -f Specify device, default is '%s'\n", DEFAULT_DEVICE);
+ fprintf(stderr, " -d Specify driver, one of:\n");
+ for (i = 0; lcd_drivertab[i].l_code != NULL; i++) {
+ fprintf(stderr, " %-10s (%s)%s\n",
+ lcd_drivertab[i].l_code, lcd_drivertab[i].l_name, (i == 0) ? " *default*" : "");
+ if (lcd_drivertab[i].l_options[0] != NULL) {
+
+ for (j = 0; lcd_drivertab[i].l_options[j] != NULL; j++)
+ fprintf(stderr, " %s\n", lcd_drivertab[i].l_options[j]);
+ }
+ }
+ fprintf(stderr, " -o Specify driver option string\n");
+ fprintf(stderr, " args Message strings. Embedded escapes supported:\n");
+ fprintf(stderr, " \\b Backspace\n");
+ fprintf(stderr, " \\f Clear display, home cursor\n");
+ fprintf(stderr, " \\n Newline\n");
+ fprintf(stderr, " \\r Carriage return\n");
+ fprintf(stderr, " \\R Reset display\n");
+ fprintf(stderr, " \\v Home cursor\n");
+ fprintf(stderr, " \\\\ Literal \\\n");
+ fprintf(stderr, " If args not supplied, strings are read from standard input\n");
+ exit(EX_USAGE);
+}
+
+static void
+do_char(struct lcd_driver *driver, char ch)
+{
+ static int esc = 0;
+
+ if (esc) {
+ switch(ch) {
+ case 'b':
+ driver->l_command(CMD_BKSP);
+ break;
+ case 'f':
+ driver->l_command(CMD_CLR);
+ break;
+ case 'n':
+ driver->l_command(CMD_NL);
+ break;
+ case 'r':
+ driver->l_command(CMD_CR);
+ break;
+ case 'R':
+ driver->l_command(CMD_RESET);
+ break;
+ case 'v':
+ driver->l_command(CMD_HOME);
+ break;
+ case '\\':
+ driver->l_putc('\\');
+ break;
+ default:
+ driver->l_command(ch);
+ break;
+ }
+ esc = 0;
+ } else {
+ if (ch == '\\') {
+ esc = 1;
+ } else {
+ if (vflag || isprint(ch))
+ driver->l_putc(ch);
+ }
+ }
+}
+
+
+/******************************************************************************
+ * Driver for the Hitachi HD44780. This is probably *the* most common driver
+ * to be found on one- and two-line alphanumeric LCDs.
+ *
+ * This driver assumes the following connections :
+ *
+ * Parallel Port LCD Module
+ * --------------------------------
+ * Strobe (1) Enable (6)
+ * Data (2-9) Data (7-14)
+ * Select In (17) RS (4)
+ * Auto Feed (14) R/W (5)
+ *
+ * In addition, power must be supplied to the module, normally with
+ * a circuit similar to this:
+ *
+ * VCC (+5V) O------o-------o--------O Module pin 2
+ * | | +
+ * / ---
+ * \ --- 1uF
+ * / | -
+ * \ <-----o--------O Module pin 3
+ * /
+ * \
+ * |
+ * GND O------o----------------O Module pin 1
+ *
+ * The ground line should also be connected to the parallel port, on
+ * one of the ground pins (eg. pin 25).
+ *
+ * Note that the pinning on some LCD modules has the odd and even pins
+ * arranged as though reversed; check carefully before connecting a module
+ * as it is possible to toast the HD44780 if the power is reversed.
+ */
+
+static int hd_fd;
+static u_int8_t hd_cbits;
+static int hd_lines = 2;
+static int hd_blink = 0;
+static int hd_cursor = 0;
+static int hd_font = 0;
+
+#define HD_COMMAND SELECTIN
+#define HD_DATA 0
+#define HD_READ 0
+#define HD_WRITE AUTOFEED
+
+#define HD_BF 0x80 /* internal busy flag */
+#define HD_ADDRMASK 0x7f /* DDRAM address mask */
+
+#define hd_sctrl(v) {u_int8_t _val; _val = hd_cbits | v; ioctl(hd_fd, PPISCTRL, &_val);}
+#define hd_sdata(v) {u_int8_t _val; _val = v; ioctl(hd_fd, PPISDATA, &_val);}
+#define hd_gdata(v) ioctl(hd_fd, PPIGDATA, &v)
+
+static void
+hd44780_output(int type, int data)
+{
+ debug(3, "%s -> 0x%02x", (type == HD_COMMAND) ? "cmd " : "data", data);
+ hd_sctrl(type | HD_WRITE | STROBE); /* set direction, address */
+ hd_sctrl(type | HD_WRITE); /* raise E */
+ hd_sdata((u_int8_t) data); /* drive data */
+ hd_sctrl(type | HD_WRITE | STROBE); /* lower E */
+}
+
+static int
+hd44780_input(int type)
+{
+ u_int8_t val;
+
+ hd_sctrl(type | HD_READ | STROBE); /* set direction, address */
+ hd_sctrl(type | HD_READ); /* raise E */
+ hd_gdata(val); /* read data */
+ hd_sctrl(type | HD_READ | STROBE); /* lower E */
+
+ debug(3, "0x%02x -> %s", val, (type == HD_COMMAND) ? "cmd " : "data");
+ return(val);
+}
+
+static void
+hd44780_prepare(char *devname, char *options)
+{
+ char *cp = options;
+
+ if ((hd_fd = open(devname, O_RDWR, 0)) == -1)
+ err(EX_OSFILE, "can't open '%s'", devname);
+
+ /* parse options */
+ while (cp && *cp) {
+ switch (*cp++) {
+ case '1':
+ hd_lines = 1;
+ break;
+ case 'B':
+ hd_blink = 1;
+ break;
+ case 'C':
+ hd_cursor = 1;
+ break;
+ case 'F':
+ hd_font = 1;
+ break;
+ default:
+ errx(EX_USAGE, "hd44780: unknown option code '%c'", *(cp-1));
+ }
+ }
+
+ /* Put LCD in idle state */
+ if (ioctl(hd_fd, PPIGCTRL, &hd_cbits)) /* save other control bits */
+ err(EX_IOERR, "ioctl PPIGCTRL failed (not a ppi device?)");
+ hd_cbits &= ~(STROBE | SELECTIN | AUTOFEED); /* set strobe, RS, R/W low */
+ debug(2, "static control bits 0x%x", hd_cbits);
+ hd_sctrl(STROBE);
+ hd_sdata(0);
+
+}
+
+static void
+hd44780_finish(void)
+{
+ close(hd_fd);
+}
+
+static void
+hd44780_command(int cmd)
+{
+ u_int8_t val;
+
+ switch (cmd) {
+ case CMD_RESET: /* full manual reset and reconfigure as per datasheet */
+ debug(1, "hd44780: reset to %d lines, %s font,%s%s cursor",
+ hd_lines, hd_font ? "5x10" : "5x7", hd_cursor ? "" : " no", hd_blink ? " blinking" : "");
+ val = 0x30;
+ if (hd_lines == 2)
+ val |= 0x08;
+ if (hd_font)
+ val |= 0x04;
+ hd44780_output(HD_COMMAND, val);
+ usleep(10000);
+ hd44780_output(HD_COMMAND, val);
+ usleep(1000);
+ hd44780_output(HD_COMMAND, val);
+ usleep(1000);
+ val = 0x08; /* display off */
+ hd44780_output(HD_COMMAND, val);
+ usleep(1000);
+ val |= 0x04; /* display on */
+ if (hd_cursor)
+ val |= 0x02;
+ if (hd_blink)
+ val |= 0x01;
+ hd44780_output(HD_COMMAND, val);
+ usleep(1000);
+ hd44780_output(HD_COMMAND, 0x06); /* shift cursor by increment */
+ usleep(1000);
+ /* FALLTHROUGH */
+
+ case CMD_CLR:
+ hd44780_output(HD_COMMAND, 0x01);
+ usleep(2000);
+ break;
+
+ case CMD_BKSP:
+ hd44780_output(HD_DATA, 0x10); /* shift cursor left one */
+ break;
+
+ case CMD_NL:
+ if (hd_lines == 2)
+ hd44780_output(HD_COMMAND, 0xc0); /* beginning of second line */
+ break;
+
+ case CMD_CR:
+ /* XXX will not work in 4-line mode, or where readback fails */
+ val = hd44780_input(HD_COMMAND) & 0x3f; /* mask character position, save line pos */
+ hd44780_output(HD_COMMAND, 0x80 | val);
+ break;
+
+ case CMD_HOME:
+ hd44780_output(HD_COMMAND, 0x02);
+ usleep(2000);
+ break;
+
+ default:
+ if (isprint(cmd)) {
+ warnx("unknown command %c", cmd);
+ } else {
+ warnx("unknown command 0x%x", cmd);
+ }
+ }
+ usleep(40);
+}
+
+static void
+hd44780_putc(int c)
+{
+ hd44780_output(HD_DATA, c);
+ usleep(40);
+}
+
diff --git a/share/examples/ppp/chap-auth b/share/examples/ppp/chap-auth
new file mode 100755
index 000000000000..91778949fea3
--- /dev/null
+++ b/share/examples/ppp/chap-auth
@@ -0,0 +1,96 @@
+#! /usr/local/bin/wish8.0 -f
+#
+# Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+#
+# Display a window to request a users CHAP secret, accepting the relevant
+# values from ppp (``set authkey !thisprogram'') and passing the entered
+# ``authname'' and ``authkey'' back to ppp.
+#
+
+set pwidth 12; # Prompt field width
+set vwidth 20; # Value field width
+set fxpad 7; # Value field width
+set fypad 3; # Value field width
+
+wm title . "PPP Authentication";
+
+# We expect three lines of input from ppp
+set hostname [gets stdin];
+set challenge [gets stdin];
+set authname [gets stdin];
+
+proc mkhalfframe { n prompt } {
+ global pwidth;
+
+ frame .$n;
+ text .$n.prompt -width $pwidth -height 1 -relief flat;
+ .$n.prompt insert 1.0 $prompt;
+ pack .$n.prompt -side left;
+ .$n.prompt configure -state disabled;
+}
+
+proc mkframe { n prompt value entry } {
+ global vwidth fxpad fypad;
+
+ mkhalfframe $n $prompt;
+ text .$n.value -width $vwidth -height 1;
+ .$n.value insert 1.0 $value;
+ pack .$n.value -side right;
+ if ($entry) {
+ # Allow entry, but don't encourage it
+ .$n.value configure -state normal -takefocus 0;
+ bind .$n.value <Return> {done};
+ } else {
+ .$n.value configure -state disabled;
+ }
+ pack .$n -side top -padx $fxpad -pady $fypad;
+}
+
+# Dump our fields to stdout and exit
+proc done {} {
+ puts [.n.value get 1.0 {end - 1 char}];
+ puts [.k.value get];
+ exit 0;
+}
+
+mkframe h "Hostname:" $hostname 0;
+mkframe c "Challenge:" $challenge 0;
+mkframe n "Authname:" $authname 1;
+
+mkhalfframe k "Authkey:";
+entry .k.value -show "*" -width $vwidth;
+pack .k.value -side right;
+bind .k.value <Return> {done};
+focus .k.value;
+pack .k -side top -padx $fxpad -pady $fypad;
+
+frame .b;
+button .b.ok -default active -text "Ok" -command {done};
+pack .b.ok -side left;
+button .b.cancel -default normal -text "Cancel" -command {exit 1};
+pack .b.cancel -side right;
+pack .b -side top -padx $fxpad -pady $fypad;
diff --git a/share/examples/ppp/login-auth b/share/examples/ppp/login-auth
new file mode 100755
index 000000000000..e3d34f89ddff
--- /dev/null
+++ b/share/examples/ppp/login-auth
@@ -0,0 +1,73 @@
+#! /usr/local/bin/wish8.0 -f
+#
+# Copyright (c) 1999 Brian Somers <brian@Awfulhak.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+#
+# Display a window to request a users password, expecting a login name
+# as an argument and outputting the password to stdout.
+#
+
+set pwidth 11; # Prompt field width
+set vwidth 20; # Value field width
+set fxpad 7; # Value field width
+set fypad 3; # Value field width
+
+wm title . "PPP Login";
+
+# Dump our password to stdout and exit
+proc done {} {
+ puts [.p.value get];
+ exit 0;
+}
+
+frame .l;
+text .l.prompt -width $pwidth -height 1 -relief flat;
+ .l.prompt insert 1.0 "Login:";
+pack .l.prompt -side left;
+ .l.prompt configure -state disabled;
+text .l.value -width $vwidth -height 1;
+ .l.value insert 1.0 $argv;
+pack .l.value -side right;
+ .l.value configure -state disabled;
+pack .l -side top -padx $fxpad -pady $fypad;
+
+frame .p;
+text .p.prompt -width $pwidth -height 1 -relief flat;
+ .p.prompt insert 1.0 "Password:";
+pack .p.prompt -side left;
+ .p.prompt configure -state disabled;
+entry .p.value -show "*" -width $vwidth;
+pack .p.value -side right;
+bind .p.value <Return> {done};
+focus .p.value;
+pack .p -side top -padx $fxpad -pady $fypad;
+
+frame .b;
+button .b.ok -default active -text "Ok" -takefocus 0 -command {done};
+pack .b.ok -side left;
+button .b.cancel -default normal -text "Cancel" -takefocus 0 -command {exit 1};
+pack .b.cancel -side right;
+pack .b -side top -padx $fxpad -pady $fypad;
diff --git a/share/examples/ppp/ppp.conf.sample b/share/examples/ppp/ppp.conf.sample
new file mode 100644
index 000000000000..67df28d23f4f
--- /dev/null
+++ b/share/examples/ppp/ppp.conf.sample
@@ -0,0 +1,788 @@
+#################################################################
+#
+# PPP Sample Configuration File
+#
+# Originally written by Toshiharu OHNO
+#
+#
+#################################################################
+
+# This file is separated into sections. Each section is named with
+# a label starting in column 0 and followed directly by a ``:''. The
+# section continues until the next label. Blank lines and characters
+# after a ``#'' are ignored (a literal ``#'' must be escaped with a ``\''
+# or quoted with ""). All commands inside sections that do not begin
+# with ``!'' (e.g., ``!include'') *must* be indented by at least one
+# space or tab or they will not be recognized!
+#
+# Lines beginning with "!include" will ``include'' another file. You
+# may want to ``!include ~/.ppp.conf'' for backwards compatibility.
+#
+
+# Default setup. Always executed when PPP is invoked.
+# This section is *not* pre-loaded by the ``load'' or ``dial'' commands.
+#
+# This is the best place to specify your modem device, its DTR rate,
+# your dial script and any logging specification. Logging specs should
+# be done first so that the results of subsequent commands are logged.
+#
+default:
+ set log Phase Chat LCP IPCP CCP tun command
+ set device /dev/cuau1
+ set speed 115200
+ set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \"\" AT \
+ OK-AT-OK ATE1Q0 OK \\dATDT\\T TIMEOUT 40 CONNECT"
+
+# Client side PPP
+#
+# Although the PPP protocol is a peer to peer protocol, we normally
+# consider the side that initiates the connection as the client and
+# the side that receives the connection as the server. Authentication
+# is required by the server either using a unix-style login procedure
+# or by demanding PAP or CHAP authentication from the client.
+#
+
+# An on demand example where we have dynamic IP addresses and wish to
+# use a unix-style login script:
+#
+# If the peer assigns us an arbitrary IP (most ISPs do this) and we
+# can't predict what their IP will be either, take a wild guess at
+# some IPs that you can't currently route to. Ppp can change this
+# when the link comes up.
+#
+# The /0 bit in "set ifaddr" says that we insist on 0 bits of the
+# specified IP actually being correct, therefore, the other side can assign
+# any IP number.
+#
+# The fourth arg to "set ifaddr" makes us send "0.0.0.0" as our requested
+# IP number, forcing the peer to make the decision. This is necessary
+# when negotiating with some (broken) ppp implementations.
+#
+# This entry also works with static IP numbers or when not in -auto mode.
+# The ``add'' line adds a `sticky' default route that will be updated if
+# and when any of the IP numbers are changed in IPCP negotiations.
+# The "set ifaddr" is required in -auto mode only.
+# It's better to put the ``add'' line in ppp.linkup when not in -auto mode.
+#
+# Finally, the ``enable dns'' line tells ppp to ask the peer for the
+# nameserver addresses that should be used. This isn't always supported
+# by the other side, but if it is, ppp will update /etc/resolv.conf with
+# the correct nameserver values at connection time.
+#
+# The login script shown says that you're expecting ``ogin:''. If you
+# don't receive that, send a ``\n'' and expect ``ogin:'' again. When
+# it's received, send ``ppp'', expect ``word:'' then send ``ppp''.
+# You *MUST* customise this login script according to your local
+# requirements.
+#
+pmdemand:
+ set phone 1234567
+ set login "ABORT NO\\sCARRIER TIMEOUT 5 ogin:--ogin: ppp word: ppp"
+ set timeout 120
+ set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.0 0.0.0.0
+ add default HISADDR
+ enable dns
+
+# If you want to use PAP or CHAP instead of using a unix-style login
+# procedure, do the following. Note, the peer suggests whether we
+# should send PAP or CHAP. By default, we send whatever we're asked for.
+#
+# You *MUST* customise ``MyName'' and ``MyKey'' below.
+#
+PAPorCHAPpmdemand:
+ set phone 1234567
+ set login
+ set authname "MyName"
+ set authkey "MyKey"
+ set timeout 120
+ set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.0 0.0.0.0
+ add default HISADDR
+ enable dns
+
+# On demand dialup example with static IP addresses:
+# Here, the local side uses 192.244.185.226 and the remote side
+# uses 192.244.176.44.
+#
+# # ppp -auto ondemand
+#
+# With static IP numbers, our setup is similar to dynamic:
+# Remember, ppp.linkup is searched for a "192.244.176.44" label, then
+# an "ondemand" label, and finally the "MYADDR" label.
+#
+ondemand:
+ set phone 1234567
+ set login "ABORT NO\\sCARRIER TIMEOUT 5 ogin:--ogin: ppp word: ppp"
+ set timeout 120
+ set ifaddr 192.244.185.226 192.244.176.44
+ add default HISADDR
+ enable dns
+
+# An on-demand dialup example using an external Terminal Adapter (TA)
+# that supports multi-link ppp itself.
+#
+# This may be specific to the AETHRA TA.
+#
+TA:
+ set phone 12345678 # Replace this with your ISPs phone number
+
+ set authname "somename" # Replace these with your login name & password.
+ set authkey "somepasswd" # This profile assumes you're using PAP or CHAP.
+
+ enable lqr echo
+ set reconnect 3 5
+ set redial 3 10
+ set lqrperiod 45
+ disable pred1 deflate mppe
+ deny pred1 deflate mppe
+
+ set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \"\" ATB41CL2048 \
+ OK-AT-OK ATB40&J3E1Q0 OK \\dATDT\\T TIMEOUT 40 CONNECT"
+ set login
+ set logout
+ set hangup
+
+ set timeout 60 300 # The minimum charge period is 5 minutes, so don't
+ # hangup before then
+
+ set device /dev/cuau0 # Or whatever
+ set speed 115200 # Use as high a speed as possible
+
+ enable dns # Ask the peer what to put in resolv.conf
+
+ # Take a wild guess at an IP number and let the other side decide
+ set ifaddr 172.16.0.1/0 212.0.0.0/0 0 0
+ add! default hisaddr
+
+ set mru 1504 # Some extra room for the MP header
+
+ set server /var/run/ppp/ppp-TA "" 0177 # The diagnostic port (-rw-------)
+
+
+# Example segments
+#
+# The following lines may be included as part of your configuration
+# section and aren't themselves complete. They're provided as examples
+# of how to achieve different things.
+
+examples:
+# Multi-phone example. Numbers separated by a : are used sequentially.
+# Numbers separated by a | are used if the previous dial or login script
+# failed. Usually, you will prefer to use only one of | or :, but both
+# are allowed.
+#
+ set phone 12345678|12345679:12345670|12345671
+#
+# Some phone numbers may include # characters - don't forget to escape
+# (or quote) them:
+#
+ set phone "12345##678"
+#
+# Ppp can accept control instructions from the ``pppctl'' program.
+# First, you must set up your control socket. It's safest to use
+# a UNIX domain socket, and watch the permissions:
+#
+ set server /var/run/ppp/internet MySecretPassword 0177
+#
+# Although a TCP port may be used if you want to allow control
+# connections from other machines:
+#
+ set server 6670 MySecretpassword
+#
+# If you don't like ppp's builtin chat, use an external one:
+#
+ set login "\"!chat \\-f /etc/ppp/ppp.dev.chat\""
+#
+# If we have a ``strange'' modem that must be re-initialized when we
+# hangup:
+#
+ set hangup "\"\" AT OK-AT-OK ATZ OK"
+#
+# To adjust logging without blowing away the setting in default:
+#
+ set log -command +tcp/ip
+#
+# To see log messages on the screen in interactive mode:
+#
+ set log local LCP IPCP CCP
+#
+# If you're seeing a lot of magic number problems and failed connections,
+# try this (see the man page):
+#
+ set openmode active 5
+#
+# For noisy lines, we may want to reconnect (up to 20 times) after loss
+# of carrier, with 3 second delays between each attempt:
+#
+ set reconnect 3 20
+#
+# When playing server for M$ clients, tell them who our NetBIOS name
+# servers are:
+#
+ set nbns 10.0.0.1 10.0.0.2
+#
+# Inform the client if they ask for our DNS IP numbers:
+#
+ enable dns
+#
+# If you don't want to tell them what's in your /etc/resolv.conf file
+# with `enable dns', override the values:
+#
+ set dns 10.0.0.1 10.0.0.2
+#
+# Some people like to prioritize DNS packets:
+#
+ set urgent udp +53
+#
+# If we're using the -nat switch, redirect ftp and http to an internal
+# machine:
+#
+ nat port tcp 10.0.0.2:ftp ftp
+ nat port tcp 10.0.0.2:http http
+#
+# or don't trust the outside at all
+#
+ nat deny_incoming yes
+#
+# I trust user brian to run ppp, so this goes in the `default' section:
+#
+ allow user brian
+#
+# But label `internet' contains passwords that even brian can't have, so
+# I empty out the user access list in that section so that only root can
+# have access:
+#
+ allow users
+#
+# I also may wish to set up my ppp login script so that it asks the client
+# for the label they wish to use. I may only want user ``dodgy'' to access
+# their own label in direct mode:
+#
+dodgy:
+ allow user dodgy
+ allow mode direct
+#
+# We don't want certain packets to keep our connection alive
+#
+ set filter alive 0 deny udp src eq 520 # routed
+ set filter alive 1 deny udp dst eq 520 # routed
+ set filter alive 2 deny udp src eq 513 # rwhod
+ set filter alive 3 deny udp src eq 525 # timed
+ set filter alive 4 deny udp src eq 137 # NetBIOS name service
+ set filter alive 5 deny udp src eq 138 # NetBIOS datagram service
+ set filter alive 6 deny tcp src eq 139 # NetBIOS session service
+ set filter alive 7 deny udp dst eq 137 # NetBIOS name service
+ set filter alive 8 deny udp dst eq 138 # NetBIOS datagram service
+ set filter alive 9 deny tcp dst eq 139 # NetBIOS session service
+ set filter alive 10 deny 0/0 MYADDR icmp # Ping to us from outside
+ set filter alive 11 permit 0/0 0/0
+#
+# And in auto mode, we don't want certain packets to cause a dialup
+#
+ set filter dial 0 deny udp src eq 513 # rwhod
+ set filter dial 1 deny udp src eq 525 # timed
+ set filter dial 2 deny udp src eq 137 # NetBIOS name service
+ set filter dial 3 deny udp src eq 138 # NetBIOS datagram service
+ set filter dial 4 deny tcp src eq 139 # NetBIOS session service
+ set filter dial 5 deny udp dst eq 137 # NetBIOS name service
+ set filter dial 6 deny udp dst eq 138 # NetBIOS datagram service
+ set filter dial 7 deny tcp dst eq 139 # NetBIOS session service
+ set filter dial 8 deny tcp finrst # Badly closed TCP channels
+ set filter dial 9 permit 0 0
+#
+# Once the line's up, allow these connections
+#
+ set filter in 0 permit tcp dst eq 113 # ident
+ set filter out 0 permit tcp src eq 113 # ident
+ set filter in 1 permit tcp src eq 23 estab # telnet
+ set filter out 1 permit tcp dst eq 23 # telnet
+ set filter in 2 permit tcp src eq 21 estab # ftp
+ set filter out 2 permit tcp dst eq 21 # ftp
+ set filter in 3 permit tcp src eq 20 dst gt 1023 # ftp-data
+ set filter out 3 permit tcp dst eq 20 # ftp-data
+ set filter in 4 permit udp src eq 53 # DNS
+ set filter out 4 permit udp dst eq 53 # DNS
+ set filter in 5 permit 192.244.191.0/24 0/0 # Where I work
+ set filter out 5 permit 0/0 192.244.191.0/24 # Where I work
+ set filter in 6 permit icmp # pings
+ set filter out 6 permit icmp # pings
+ set filter in 7 permit udp dst gt 33433 # traceroute
+ set filter out 7 permit udp dst gt 33433 # traceroute
+
+#
+# ``dodgynet'' is an example intended for an autodial configuration which
+# is connecting a local network to a host on an untrusted network.
+dodgynet:
+ set log Phase # Log link uptime
+ allow mode auto # For autoconnect only
+ set device /dev/cuau1 # Define modem device and speed
+ set speed 115200
+ deny lqr # Don't support LQR
+ set phone 0W1194 # Remote system phone number,
+ set authname "pppLogin" # login
+ set authkey "MyPassword" # and password
+ set dial "ABORT BUSY ABORT NO\\sCARRIER \ # Chat script to dial the peer
+ TIMEOUT 5 \"\" ATZ OK-ATZ-OK \
+ ATE1Q0M0 OK \\dATDT\\T \
+ TIMEOUT 40 CONNECT"
+ set login "TIMEOUT 10 \"\" \"\" \ # And to login to remote system
+ gin:--gin: \\U word: \\P"
+
+ # Drop the link after 15 minutes of inactivity
+ # Inactivity is defined by the `set filter alive' line below
+ set timeout 900
+
+ # Hard-code remote system to appear within local subnet and use proxy arp
+ # to make this system the gateway for the rest of the local network
+ set ifaddr 172.17.20.247 172.17.20.248 255.255.240.0
+ enable proxy
+
+ # Allow any TCP packet to keep the link alive
+ set filter alive 0 permit tcp
+
+ # Only allow dialup to be triggered by http, rlogin, rsh, telnet, ftp or
+ # private TCP ports 24 and 4000
+ set filter dial 0 7 0 0 tcp dst eq http
+ set filter dial 1 7 0 0 tcp dst eq login
+ set filter dial 2 7 0 0 tcp dst eq shell
+ set filter dial 3 7 0 0 tcp dst eq telnet
+ set filter dial 4 7 0 0 tcp dst eq ftp
+ set filter dial 5 7 0 0 tcp dst eq 24
+ set filter dial 6 deny ! 0 0 tcp dst eq 4000
+
+ # From hosts on a couple of local subnets to the remote peer
+ # If the remote host allowed IP forwarding and we wanted to use it, the
+ # following rules could be split into two groups to separately validate
+ # the source and destination addresses.
+ set filter dial 7 permit 172.17.16.0/20 172.17.20.248
+ set filter dial 8 permit 172.17.36.0/22 172.17.20.248
+ set filter dial 9 permit 172.17.118.0/26 172.17.20.248
+ set filter dial 10 permit 10.123.5.0/24 172.17.20.248
+
+ # Once the link's up, limit outgoing access to the specified hosts
+ set filter out 0 4 172.17.16.0/20 172.17.20.248
+ set filter out 1 4 172.17.36.0/22 172.17.20.248
+ set filter out 2 4 172.17.118.0/26 172.17.20.248
+ set filter out 3 deny ! 10.123.5.0/24 172.17.20.248
+
+ # Allow established TCP connections
+ set filter out 4 permit 0 0 tcp estab
+
+ # And new connections to http, rlogin, rsh, telnet, ftp and ports
+ # 24 and 4000
+ set filter out 5 permit 0 0 tcp dst eq http
+ set filter out 6 permit 0 0 tcp dst eq login
+ set filter out 7 permit 0 0 tcp dst eq shell
+ set filter out 8 permit 0 0 tcp dst eq telnet
+ set filter out 9 permit 0 0 tcp dst eq ftp
+ set filter out 10 permit 0 0 tcp dst eq 24
+ set filter out 11 permit 0 0 tcp dst eq 4000
+
+ # And outgoing icmp
+ set filter out 12 permit 0 0 icmp
+
+ # Once the link's up, limit incoming access to the specified hosts
+ set filter in 0 4 172.17.20.248 172.17.16.0/20
+ set filter in 1 4 172.17.20.248 172.17.36.0/22
+ set filter in 2 4 172.17.20.248 172.17.118.0/26
+ set filter in 3 deny ! 172.17.20.248 10.123.5.0/24
+
+ # Established TCP connections and non-PASV FTP
+ set filter in 4 permit 0/0 0/0 tcp estab
+ set filter in 5 permit 0/0 0/0 tcp src eq 20
+
+ # Useful ICMP messages
+ set filter in 6 permit 0/0 0/0 icmp src eq 3
+ set filter in 7 permit 0/0 0/0 icmp src eq 4
+ set filter in 8 permit 0/0 0/0 icmp src eq 11
+ set filter in 9 permit 0/0 0/0 icmp src eq 12
+
+ # Echo reply (local systems can ping the remote host)
+ set filter in 10 permit 0/0 0/0 icmp src eq 0
+
+ # And the remote host can ping the local gateway (only)
+ set filter in 11 permit 0/0 172.17.20.247 icmp src eq 8
+
+
+# Server side PPP
+#
+# If you want the remote system to authenticate itself, you must insist
+# that the peer uses CHAP or PAP with the "enable" keyword. Both CHAP and
+# PAP are disabled by default. You may enable either or both. If both
+# are enabled, CHAP is requested first. If the client doesn't agree, PAP
+# will then be requested.
+#
+# Note: If you use the getty/login process to authenticate users, you
+# don't need to enable CHAP or PAP, but the user that has logged
+# in *MUST* be a member of the ``network'' group (in /etc/group).
+#
+# Note: Chap80 and chap81 are Microsoft variations of standard chap (05).
+#
+# If you wish to allow any user in the passwd database ppp access, you
+# can ``enable passwdauth'', but this will only work with PAP.
+#
+# When the peer authenticates itself, we use ppp.secret for verification
+# (although refer to the ``set radius'' command below for an alternative).
+#
+# Note: We may supply a third field in ppp.secret specifying the IP
+# address for that user, a fourth field to specify the
+# ppp.link{up,down} label to use and a fifth field to specify
+# callback characteristics.
+#
+# The easiest way to allow transparent LAN access to your dialin users
+# is to assign them a number from your local LAN and tell ppp to make a
+# ``proxy'' arp entry for them. In this example, we have a local LAN
+# with IP numbers 10.0.0.1 - 10.0.0.99, and we assign numbers to our
+# ppp clients between 10.0.0.100 and 10.0.0.199. It is possible to
+# override the dynamic IP number with a static IP number specified in
+# ppp.secret.
+#
+# Ppp is launched with:
+# # ppp -direct server
+#
+server:
+ enable chap chap80 chap81 pap passwdauth
+ enable proxy
+ set ifaddr 10.0.0.1 10.0.0.100-10.0.0.199
+ accept dns
+
+# Example of a RADIUS configuration:
+# If there are one or more radius servers available, we can use them
+# instead of the ppp.secret file. Simply put then in a radius
+# configuration file (usually /etc/radius.conf) and give ppp the
+# file name.
+# Ppp will use the FRAMED characteristics supplied by the radius server
+# to configure the link.
+
+radius-server:
+ load server # load in the server config from above
+ set radius /etc/radius.conf
+
+
+# Example to connect using a null-modem cable:
+# The important thing here is to allow the lqr packets on both sides.
+# Without them enabled, we can't tell if the line's dropped - there
+# should always be carrier on a direct connection.
+# Here, the server sends lqr's every 10 seconds and quits if five in a
+# row fail.
+#
+# Make sure you don't have "deny lqr" in your default: on the client !
+# If the peer denies LQR, we still send ECHO LQR packets at the given
+# lqrperiod interval (ppp-style-pings).
+#
+direct-client:
+ set dial
+ set device /dev/cuau0
+ set sp 115200
+ set timeout 900
+ set lqrperiod 10
+ set log Phase Chat LQM
+ set login "ABORT NO\\sCARRIER TIMEOUT 5 ogin:--ogin: ppp word: ppp HELLO"
+ set ifaddr 10.0.4.2 10.0.4.1
+ enable lqr echo
+ accept lqr
+
+direct-server:
+ set timeout 0
+ set lqrperiod 10
+ set log Phase LQM
+ set ifaddr 10.0.4.1 10.0.4.2
+ enable lqr echo
+ accept lqr
+
+
+# Example to connect via compuserve
+# Compuserve insists on 7 bits even parity during the chat phase. Modem
+# parity is always reset to ``none'' after the link has been established.
+#
+compuserve:
+ set phone 1234567
+ set parity even
+ set login "TIMEOUT 100 \"\" \"\" Name: CIS ID: 999999,9999/go:pppconnect \
+ word: XXXXXXXX PPP"
+ set timeout 300
+ set ifaddr 10.0.0.1/0 10.0.0.2/0 255.255.255.0 0.0.0.0
+ delete ALL
+ add default HISADDR
+
+
+# Example for PPP over TCP.
+# We assume that inetd on tcpsrv.mynet has been
+# configured to run "ppp -direct tcp-server" when it gets a connection on
+# port 1234 with an entry something like this in /etc/inetd.conf.:
+#
+# ppp stream tcp nowait root /usr/sbin/ppp ppp -direct tcp-server
+#
+# with this in /etc/services:
+#
+# ppp 6671/tcp
+#
+# Read the man page for further details.
+#
+# Note, we assume we're using a binary-clean connection. If something
+# such as `rlogin' is involved, you may need to ``set escape 0xff''
+#
+tcp-client:
+ set device tcpsrv.mynet:6671
+ set dial
+ set login
+ set ifaddr 10.0.5.1 10.0.4.1 255.255.255.0
+
+tcp-server:
+ set ifaddr 10.0.4.1 10.0.5.1 255.255.255.0
+
+
+# Using UDP is also possible with this in /etc/inetd.conf:
+#
+# ppp dgram udp wait root /usr/sbin/ppp ppp -direct udp-server
+#
+# and this in /etc/services:
+#
+# ppp 6671/udp
+#
+udp-client:
+ set device udpsrv.mynet:6671/udp
+ set dial
+ set login
+ set ifaddr 10.0.5.1 10.0.4.1 255.255.255.0
+
+udp-server:
+ set ifaddr 10.0.4.1 10.0.5.1 255.255.255.0
+
+
+# Example for PPP testing.
+# If you want to test ppp, do it through the loopback interface:
+#
+# Requires a line in /etc/services:
+# ppploop 6671/tcp # loopback ppp daemon
+#
+# and a line in /etc/inetd.conf:
+# ppploop stream tcp nowait root /usr/sbin/ppp ppp -direct inet-loop-in
+#
+inet-loop:
+ set timeout 0
+ set log phase chat connect lcp ipcp command
+ set device localhost:ppploop
+ set dial
+ set login
+ set ifaddr 127.0.0.2 127.0.0.3
+ set server /var/run/ppp/loop "" 0177
+
+inet-loop-in:
+ set timeout 0
+ set log phase lcp ipcp command
+ allow mode direct
+
+# Example of a VPN.
+# If you're going to create a tunnel through a public network, your VPN
+# should be set up something like this:
+#
+# You should already have set up ssh using ssh-agent & ssh-add.
+#
+sloop:
+ load inet-loop
+ # Passive mode allows ssh plenty of time to establish the connection
+ set openmode passive
+ set device "!ssh whatevermachine /usr/sbin/ppp -direct inet-loop-in"
+
+
+# or a better VPN solution (which doesn't run IP over a reliable
+# protocol like tcp) may be:
+#
+vpn-client:
+ set device udpsrv.mynet:1234/udp # PPP over UDP
+ set dial
+ set login
+ set ifaddr 10.0.5.1 10.0.4.1 255.255.255.0
+ disable deflate pred1
+ deny deflate pred1
+ enable MPPE # With encryption
+ accept MPPE
+
+vpn-server:
+ set ifaddr 10.0.4.1 10.0.5.1 255.255.255.0
+ disable deflate pred1
+ deny deflate pred1
+ enable MPPE
+ accept MPPE
+ enable chap81 # Required for MPPE
+
+# Example of non-PPP callback.
+# If you wish to connect to a server that will dial back *without* using
+# the ppp callback facility (rfc1570), take advantage of the fact that
+# ppp doesn't look for carrier 'till `set login' is complete:
+#
+# Here, we expect the server to say DIALBACK then disconnect after
+# we've authenticated ourselves. When this has happened, we wait
+# 60 seconds for a RING.
+#
+# Note, it's important that we tell ppp not to expect carrier, otherwise
+# we'll drop out at the ``NO CARRIER'' stage.
+#
+dialback:
+ set dial "ABORT BUSY ABORT NO\\sCARRIER TIMEOUT 5 \"\" ATZ OK-ATZ-OK \
+ ATDT\\T TIMEOUT 60 CONNECT"
+ set cd off
+ set login "TIMEOUT 5 ogin:--ogin: ppp word: ppp TIMEOUT 15 DIALBACK \
+ \"\" NO\\sCARRIER \"\" TIMEOUT 60 RING ATA CONNECT"
+
+# Example of PPP callback.
+# Alternatively, if the peer is using the PPP callback protocol, we're
+# happy either with ``auth'' style callback where the server dials us
+# back based on what we authenticate ourselves with, ``cbcp'' style
+# callback (invented by Microsoft but not agreed by the IETF) where
+# we negotiate callback *after* authentication or E.164 callback where
+# we specify only a phone number. I would recommend only ``auth'' and/or
+# ``cbcp'' callback methods.
+# For ``cbcp'', we insist that we choose ``1234567'' as the number that
+# the server must call back.
+#
+callback:
+ load pmdemand # load in the pmdemand config
+ set callback auth cbcp e.164 1234567
+ set cbcp 1234567
+
+# If we're running a ppp server that wants to only call back microsoft
+# clients on numbers configured in /etc/ppp/ppp.secret (the 5th field):
+#
+callback-server:
+ load server
+ set callback cbcp
+ set cbcp
+ set log +cbcp
+ set redial 3 1
+ set device /dev/cuau0
+ set speed 115200
+ set dial "TIMEOUT 10 \"\" AT OK-AT-OK ATDT\\T CONNECT"
+
+# Or if we want to allow authenticated clients to specify their own
+# callback number:
+#
+callback-server-client-decides:
+ load callback-server
+ set cbcp *
+
+# Multilink mode is available (rfc1990).
+# To enable multi-link capabilities, you must specify a MRRU. 1500 is
+# a reasonable value. To create new links, use the ``clone'' command
+# to duplicate an existing link. If you already have more than one
+# link, you must specify which link you wish to run the command on via
+# the ``link'' command.
+#
+# It's worth increasing your MTU and MRU slightly in multi-link mode to
+# prevent full packets from being fragmented.
+#
+# You can now ``dial'' specific links, or even dial all links at the
+# same time. The `dial' command may also be prefixed with a specific
+# link that should do the dialing.
+#
+mloop:
+ load loop
+ set device /dev/cuau0 /dev/cuau1 /dev/cuau2 # Use any of these devices
+ set mode interactive
+ set mrru 1500
+ set mru 1504 # Room for the MP header
+ clone 1 2 3
+ link deflink remove
+ # dial
+ # link 2 dial
+ # link 3 dial
+
+mloop-in:
+ set timeout 0 # No idle timer
+ set log tun phase
+ allow mode direct
+ set mrru 1500
+ set mru 1504 # Room for the MP header
+
+# User supplied authentication:
+# It's possible to run ppp in the background while specifying a
+# program to use to obtain authentication details on demand.
+# This program would usually be a simple GUI that presents a
+# prompt to a known user. The ``chap-auth'' program is supplied
+# as an example (and requires tcl version 8.0).
+#
+CHAPprompt:
+ load PAPorCHAPpmdemand
+ set authkey !/usr/share/examples/ppp/chap-auth
+
+# It's possible to do the same sort of thing at the login prompt.
+# Here, after sending ``brian'' in response to the ``name'' prompt,
+# we're prompted with ``code:''. A window is then displayed on the
+# ``keep:0.0'' display and the typed response is sent to the peer
+# as the password. We then expect to see ``MTU'' and ``.'' in the
+# servers response.
+#
+loginprompt:
+ load pmdemand
+ set authname "brian"
+ set login "ABORT NO\\sCARRIER TIMEOUT 15 \"\" \"\" name:--name: \\U \
+ code: \"!/usr/share/examples/ppp/login-auth -display keep:0.0 \
+ AUTHNAME\" MTU \\c ."
+
+# ppp supports ppp over ethernet (PPPoE). Beware, many PPP servers cache
+# the MAC address that connects to them, making it impossible to switch
+# your PPPoE connection between machines.
+#
+# The current implementation requires Netgraph, so it doesn't work with
+# OpenBSD or NetBSD.
+#
+# The client should be something like this:
+#
+pppoe:
+ set device PPPoE:de0:pppoe-in
+ enable lqr echo
+ set cd 5
+ set dial
+ set login
+ set redial 0 0
+
+# And the server should be running
+#
+# /usr/libexec/pppoed -p pppoe-in fxp0
+#
+# See rc.conf(5)
+#
+pppoe-in:
+ allow mode direct # Only for use on server-side
+ enable lqr echo proxy # Enable LQR and proxy-arp
+ enable chap pap passwdauth # Force client authentication
+ set ifaddr 10.0.0.1 10.0.0.100-10.0.0.199 # Hand out up to 100 IP numbers
+ accept dns # Allow DNS negotiation
+
+# It's possible to run ppp back-to-back with itself. This is useful
+# for testing.
+#
+# When testing scalability and concurrency, the following profile might
+# be used.
+#
+# Note, you'll have to make some other machine adjustments:
+#
+# o Bump maxusers in your kernel configuration to about 256 so that there
+# are enough process table slots.
+# o Bump system file descriptors with ``sysctl kern.maxfiles=20480''. You'll
+# need 3 descriptors per ppp process (assuming no server socket).
+#
+# You can now create 2000 processes (1000 pairs) with:
+#
+# n=0
+# while [ $n -lt 1000 ]; do ppp -b loop; n=$(($n + 1)); done
+#
+# If you want to test concurrency, try using ``ppp -dd loop'' instead.
+#
+loop:
+ set timeout 0
+ set log
+ set device "!ppp -direct loop-in"
+ set dial
+ set login
+ set ifaddr 10.0.1.1/0 10.0.10.1-10.0.19.255
+ disable deflate pred1 mppe
+ deny deflate pred1 mppe
+
+loop-in:
+ set timeout 0
+ set log
+ allow mode direct
+ set ifaddr 10.0.10.1/0 10.0.1.1-10.0.9.255
+ disable deflate pred1 mppe
+ deny deflate pred1 mppe
diff --git a/share/examples/ppp/ppp.conf.span-isp b/share/examples/ppp/ppp.conf.span-isp
new file mode 100644
index 000000000000..b1c3a143c633
--- /dev/null
+++ b/share/examples/ppp/ppp.conf.span-isp
@@ -0,0 +1,193 @@
+
+# This advanced ppp configuration file explains how to implement
+# the following:
+#
+# ------------- ------------- -------------
+# | host1 | | host2 | | host3 |
+# ------------- ------------- -------------
+# | | |
+# |---------------------- LAN ----------------------|
+# |
+# -------------
+# | Gateway |
+# -------------
+# |
+# -----------------------------------
+# | | | |
+# isp1 isp2 isp3 ispN
+# | | | |
+# -----------------------------------
+# |
+# ------------
+# | Receiver |
+# ------------
+# |
+# Internet
+#
+# The connection is implemented so that any ISP connection can go down
+# without loss of connectivity between the LAN and the Internet. It is
+# of course also possible to shut down any link manually.
+#
+# There is a working example in ppp.*.span-isp.working that can be tested
+# on a single machine !
+#
+#
+# Prerequisites:
+#
+# o The Receiver machine must be in the outside world and must be willing
+# to accept a multilink ppp connection over UDP, assigning a routable IP
+# number to the Gateway machine. This probably means that it must be
+# a *BSD box as I know of no other ppp implementations that can use UDP
+# as a transport.
+#
+# o The Receiver machine must be multi-homed with at least N+1 addresses
+# where N is the maximun number of ISPs that you wish to use
+# simultaneously. We assume the IP numbers to be RIP1, RIP2 ... RIPN.
+# REAL-LOCAL-IP is the real IP number of the Receiver machine (and must
+# not be the same as any of the RIP* numbers).
+#
+# o Both the Gateway and the Receiver machines must have several tun
+# interfaces configured into the kernel (see below).
+#
+# o Both the Gateway and the Receiver machines must have the following
+# entry in /etc/services:
+#
+# ppp 6671/udp
+#
+# The port number isn't important, but it must be consistent across
+# machines.
+#
+# o The Receiver machine must have the following entry in
+# /etc/inetd.conf:
+#
+# ppp dgram udp wait root /usr/sbin/ppp ppp -direct vpn-in
+#
+# Note: Because inetd ``wait''s for ppp to finish, a single ppp
+# invocation receives all incoming packets. This creates
+# havoc with LQR magic number checks, so LQR *must not* be
+# enabled.
+# Also, -direct invocations of ppp do sendto()s using the
+# address that was last recvfrom()d. This means that the
+# returning traffic is a bit unbalanced. Perhaps ppp should
+# be smart enough to automatically clone an existing link
+# when it detects a new incoming address.... tricky !
+#
+# If you use ppp to connect to your ISPs, the isp* profiles shold be used,
+# resulting in the vpn* profiles being called from ppp.linkup.span-isp.
+# These invocations will bond together into a MP ppp invocation.
+#
+# If the link to your ISP is via another type of interface (cable modem
+# etc), simply configure the interface with a netmask of 0xffffffff and
+# add a route to RIPN via the interface address (no default). You can
+# then start ppp using the vpn-nic label.
+#
+# The Receiver machine should have N tun interfaces (where N is the maximum
+# number of ISPs that you wish to use simultaneously). The Gateway machine
+# requires N interfaces plus an additional N interfaces (total 2 * N) if
+# you're using ppp to talk to the ISPs.
+
+# Using ppp to connect to your ISPs (PPP over UDP over PPP):
+#
+# When we connect to our ISPs using ppp, we start the MP ppp invocation
+# from ppp.linkup (see ppp.linkup.span-isp) for each link. We also remove
+# the link from ppp.linkdown (see ppp.linkdown.span-isp). This is necessary
+# because relying on our LQR strategy (dropping the link after 5 missing
+# replies) is just too slow to be practical in this environment.
+#
+# This works because the MP invocations are smart enough to recognise that
+# another process is already running and to pass the link over to that
+# running version.
+#
+# Only the ISP links should be started manually. When they come up, they'll
+# start the MP invocation.
+
+default:
+ set speed 115200
+ set device /dev/cuau0 /dev/cuau1 /dev/cuau2 /dev/cuau3
+ set dial "ABORT BUSY ABORT NO\\sCARRIER ABORT NO\\sDIAL\\sTONE TIMEOUT 4 \
+ \"\" ATZ OK-ATZ-OK ATDT\\T TIMEOUT 60 CONNECT \\c \\n"
+ set login
+ set redial 3 5
+ set timeout 0
+ enable lqr echo
+ set lqrperiod 15
+
+isp1:
+ set phone "1234567"
+ set authname "isp1name"
+ set authkey "isp1key"
+ add! RIP1/32 HISADDR
+
+isp2:
+ set phone "2345678"
+ set authname "isp2name"
+ set authkey "isp2key"
+ add! RIP2/32 HISADDR
+
+ispN:
+ set phone "3456789"
+ set authname "ispNname"
+ set authkey "ispNkey"
+ add! RIPN/32 HISADDR
+
+
+# Our MP version of ppp. vpn is a generic label used by each of the
+# other vpn invocations by envoking ppp with both labels (see
+# ppp.linkup.span-isp).
+# Each ``set device'' command tells ppp to use UDP packets destined for
+# the given IP/port as the link (transport). The routing table will
+# ensure that these UDP packets use the correct ISP connection.
+
+vpn:
+ set enddisc LABEL
+ set speed sync
+ set mrru 1500
+ set mru 1504 # Room for the MP header
+ nat enable yes
+ set authname "vpnname"
+ set authkey "vpnkey"
+ add! default HISADDR
+ disable deflate pred1 lqr
+ deny deflate pred1
+
+vpn1:
+ rename 1
+ set device RIP1:ppp/udp
+
+vpn2:
+ rename 2
+ set device RIP2:ppp/udp
+
+vpnN:
+ rename N
+ set device RIPN:ppp/udp
+
+vpn-nic:
+ load vpn
+ clone 1 2 N
+ link deflink rm
+ link 1 set device RIP1:ppp/udp
+ link 2 set device RIP2:ppp/udp
+ link N set device RIPN:ppp/udp
+
+# The Receiver profile is a bit more straight forward, as it doesn't need
+# to get bogged down with sublinks. Replace REAL-ASSIGNED-IP with the
+# IP number to be assigned to the Gateway machine. Replace REAL-LOCAL-IP
+# with the real IP number of the Receiver machine.
+#
+# No other entries are required on the Receiver machine, and this entry
+# is not required on the Gateway machine. The Receiver machine also
+# requires the contents of ppp.secret.span-isp.
+#
+# Of course it's simple to assign an IP block to the client with a simple
+# ``add'' command, and then have the client use those IP numbers on its
+# LAN rather than using ``nat enable yes''.
+
+vpn-in:
+ set enddisc label
+ set speed sync
+ set mrru 1500
+ set mru 1504 # Room for the MP header
+ enable chap
+ disable lqr
+ set ifaddr REAL-LOCAL-IP REAL-ASSIGNED-IP
diff --git a/share/examples/ppp/ppp.conf.span-isp.working b/share/examples/ppp/ppp.conf.span-isp.working
new file mode 100644
index 000000000000..312a1de4c401
--- /dev/null
+++ b/share/examples/ppp/ppp.conf.span-isp.working
@@ -0,0 +1,106 @@
+
+# This is a working example of ppp.conf.span-isp that uses ppp connections
+# to the same machine through 3 null-modem serial cables.
+#
+# cuaD03 <-> cuaD04
+# cuaD01 <-> cuaD06
+# cuaD00 <-> cuaD07
+#
+# with gettys running on cuaD04, cuaD06 and cuaD07. The gettytab entry
+# for these devices has a pp= capability that references a script that
+# says:
+#
+# #! /bin/sh
+# tty=$(tty)
+# exec /usr/sbin/pppin -direct isp-in-${tty#${tty%?}}
+#
+# The whole thing is brought up with these commands:
+#
+# ppp -b isp1
+# ppp -b isp2
+# ppp -b isp3
+#
+# Something rather strange happens here.
+# If you connect to the vpn-in diagnostic socket with ``pppctl
+# /var/run/ppp/vpn-in'' and do a ``show links'', only a single link shows up.
+# If you connect to the vpn diagnostic socket (which is created in
+# ppp.linkup.span-isp.working, you see three links. This is because inetd
+# is told to ``wait'' for ppp to finish and the receiving ppp gets to
+# handle all incoming packets on the first descriptor.
+#
+# This is why enabling LQR won't work - VPN-IN has magic number problems,
+# fails to reply to LQRs and the VPN invocations end up shutting down.
+#
+# If anyone can come up with a better way of doing PPP over UDP I'd be
+# interrested to hear it. Currently, the server doesn't connect() or
+# bind().... but the client connect()s. Is there any other way ?
+#
+# Answers on a postcard please ! (to brian@Awfulhak.org)
+#
+
+default:
+ set speed 115200
+ set device /dev/cuaD00 /dev/cuaD01 /dev/cuaD03
+ set dial
+ set login
+ set redial 3 5
+ set timeout 0
+ enable lqr echo
+ set lqrperiod 15
+
+isp1:
+ set authname "isp1name"
+ set authkey "isp1key"
+
+isp2:
+ set authname "isp2name"
+ set authkey "isp2key"
+
+isp3:
+ set authname "isp3name"
+ set authkey "isp3key"
+
+
+vpn:
+ set enddisc LABEL
+ set speed sync
+ set mrru 1500
+ set mru 1504 # Room for the MP header
+ set authname "vpnname"
+ set authkey "vpnkey"
+ add! default HISADDR
+ disable deflate pred1 lqr
+ deny deflate pred1
+
+vpn1:
+ rename 1
+ set device 127.0.2.7:ppp/udp
+
+vpn2:
+ rename 2
+ set device 127.0.2.6:ppp/udp
+
+vpn3:
+ rename 3
+ set device 127.0.2.4:ppp/udp
+
+
+vpn-in:
+ set enddisc label
+ set speed sync
+ set mrru 1500
+ set mru 1504 # Room for the MP header
+ enable chap
+ disable lqr
+ set ifaddr 127.0.0.2 127.0.0.3
+ set server /var/run/ppp/vpn-in "" 0177
+
+
+isp-in-7:
+ set ifaddr 127.0.2.7 127.0.3.7
+
+isp-in-6:
+ set ifaddr 127.0.2.6 127.0.3.6
+
+isp-in-4:
+ set ifaddr 127.0.2.4 127.0.3.4
diff --git a/share/examples/ppp/ppp.linkdown.sample b/share/examples/ppp/ppp.linkdown.sample
new file mode 100644
index 000000000000..1507f8c7c543
--- /dev/null
+++ b/share/examples/ppp/ppp.linkdown.sample
@@ -0,0 +1,33 @@
+#########################################################################
+#
+# Example of ppp.linkdown file
+#
+# This file is checked when ppp closes a connection.
+# ppp searches the labels in this file as follows:
+#
+# 1) The label that matches the IP number assigned to our side.
+#
+# 2) The label specified on the command line to ppp.
+#
+# 3) If no label has been found, use MYADDR if it exists.
+#
+#
+#
+#########################################################################
+
+# We don't really need to do much here. If we have notified a DNS
+# of our temporary IP number, we may want to ``un-notify'' them.
+#
+# If you're into sound effects when the link goes down, you can run
+# ``auplay'' (assuming NAS is installed and configured).
+#
+MYADDR:
+ !bg /usr/local/bin/auplay /etc/ppp/linkdown.au
+
+# If you're running ``ppp -auto -nat dynamic-nat-auto'', and are
+# assigned a dynamic IP number by the peer, this may be worth while
+# to keep the interface aliases to a minimum (see ``enable iface-alias''
+# in the man page):
+#
+dynamic-nat-auto:
+ iface clear
diff --git a/share/examples/ppp/ppp.linkdown.span-isp b/share/examples/ppp/ppp.linkdown.span-isp
new file mode 100644
index 000000000000..a9cdcfc8d488
--- /dev/null
+++ b/share/examples/ppp/ppp.linkdown.span-isp
@@ -0,0 +1,16 @@
+
+# Refer to ppp.conf.span-isp for a description of what this file is for.
+# This file is only required on the Gateway machine.
+
+# The ISP links start our MP version of ppp as they come up
+isp1:
+ !bg pppctl /var/run/ppp/vpn link 1 close
+
+isp2:
+ !bg pppctl /var/run/ppp/vpn link 2 close
+
+ispN:
+ !bg pppctl /var/run/ppp/vpn link N close
+
+vpn:
+ set server none
diff --git a/share/examples/ppp/ppp.linkdown.span-isp.working b/share/examples/ppp/ppp.linkdown.span-isp.working
new file mode 100644
index 000000000000..29ce3924e95c
--- /dev/null
+++ b/share/examples/ppp/ppp.linkdown.span-isp.working
@@ -0,0 +1,16 @@
+
+# This is a working example of ppp.linkdown.span-isp that uses ppp connections
+# to the same machine through 3 null-modem serial cables.
+
+# The ISP links start our MP version of ppp as they come up
+isp1:
+ !bg pppctl /var/run/ppp/vpn link 1 close
+
+isp2:
+ !bg pppctl /var/run/ppp/vpn link 2 close
+
+isp3:
+ !bg pppctl /var/run/ppp/vpn link 3 close
+
+vpn:
+ set server none
diff --git a/share/examples/ppp/ppp.linkup.sample b/share/examples/ppp/ppp.linkup.sample
new file mode 100644
index 000000000000..bce44414e880
--- /dev/null
+++ b/share/examples/ppp/ppp.linkup.sample
@@ -0,0 +1,53 @@
+#########################################################################
+#
+# Example of ppp.linkup file
+#
+# This file is checked when ppp establishes a connection.
+# ppp searches the labels in this file as follows:
+#
+# 1) The label that matches the IP number assigned to our side.
+#
+# 2) The label specified on the command line to ppp.
+#
+# 3) If no label has been found, use MYADDR if it exists.
+#
+#
+#
+#########################################################################
+
+# It is no longer necessary to re-add the default route here as our
+# ppp.conf route is `sticky' (see the man page).
+# If you're into sound effects when the link comes up, you can run
+# ``auplay'' (assuming NAS is installed and configured).
+#
+MYADDR:
+ !bg /usr/X11R6/bin/auplay /etc/ppp/linkup.au
+
+# If we've got 192.244.176.32 as our address, then regard peer as a gateway
+# to 192.244.176.0 network. This may also be done in ppp.conf instead.
+#
+192.244.176.32:
+ add 192.244.176.0 0 HISADDR
+
+# You may want to execute a script after connecting. This script can do
+# nice things such as kick off "sendmail -q", "popclient my.isp" and
+# "slurp -d news". It can be passed MYADDR, HISADDR and INTERFACE
+# as arguments too - useful for informing a DNS of your assigned IP.
+#
+# NOTE: It's vital that you use ``!bg'' rather than ``!'' if the program
+# you're running will take some time or will require network
+# connectivity. Using ``!'' will delay ppp 'till the completion
+# of the program being run!
+#
+# You may also want some sound effects....
+#
+pmdemand:
+ !bg /etc/ppp/ppp.etherup.pmdemand
+ ! sh -c "cat /etc/ppp/linkup.au >/dev/audio"
+
+# If your minimum call charge is 5 minutes, you may as well stay on
+# the line for that amount of time. If we want a 60 second subsequent
+# timeout, set your timeout to 300 in ppp.conf and then do this:
+#
+min5minutes:
+ !bg sh -c "sleep 240; pppctl -p mypassword 3000 set timeout 60"
diff --git a/share/examples/ppp/ppp.linkup.span-isp b/share/examples/ppp/ppp.linkup.span-isp
new file mode 100644
index 000000000000..819604d7fd22
--- /dev/null
+++ b/share/examples/ppp/ppp.linkup.span-isp
@@ -0,0 +1,16 @@
+
+# Refer to ppp.conf.span-isp for a description of what this file is for.
+# This file is only required on the Gateway machine.
+
+# The ISP links start our MP version of ppp as they come up
+isp1:
+ !bg ppp -background vpn1 vpn
+
+isp2:
+ !bg ppp -background vpn2 vpn
+
+ispN:
+ !bg ppp -background vpnN vpn
+
+vpn:
+ set server /var/run/ppp/vpn "" 0177
diff --git a/share/examples/ppp/ppp.linkup.span-isp.working b/share/examples/ppp/ppp.linkup.span-isp.working
new file mode 100644
index 000000000000..6c451a94ba20
--- /dev/null
+++ b/share/examples/ppp/ppp.linkup.span-isp.working
@@ -0,0 +1,16 @@
+
+# This is a working example of ppp.linkup.span-isp that uses ppp connections
+# to the same machine through 3 null-modem serial cables.
+
+# The ISP links start our MP version of ppp as they come up
+isp1:
+ !bg ppp -background vpn1 vpn
+
+isp2:
+ !bg ppp -background vpn2 vpn
+
+isp3:
+ !bg ppp -background vpn3 vpn
+
+vpn:
+ set server /var/run/ppp/vpn "" 0177
diff --git a/share/examples/ppp/ppp.secret.sample b/share/examples/ppp/ppp.secret.sample
new file mode 100644
index 000000000000..8104872b0456
--- /dev/null
+++ b/share/examples/ppp/ppp.secret.sample
@@ -0,0 +1,40 @@
+##################################################
+#
+# Example of ppp.secret file
+#
+# This file is used to authenticate incoming connections.
+# You must ``enable'' either PAP or CHAP in your ppp.conf file.
+# The peer may then use any of the Authname/Authkey pairs listed.
+# Additionally, if ``passwdauth'' is enabled and an entry isn't
+# found in this file, the passwd(5) database is used.
+#
+# If the password is specified as "*", look it up in passwd(5).
+# This doesn't work for CHAP connections as ppp must have access
+# to the unencrypted password for CHAP.
+#
+# If an IP address or address range is given as the third field, it
+# will be assigned to the peer. A ``*'' or an empty field may be
+# used as a placeholder if you do not wish to override the IP
+# address, but wish to specify further fields.
+#
+# If a label is given as the forth field, it is used when reading
+# the ppp.linkup and ppp.linkdown files. A ``*'' or an empty field
+# can be used as a placeholder if you do not wish to override the
+# label, but wish to specify further fields.
+#
+# If a phone number or list of phone numbers is given as the fifth
+# field, these numbers will be used to call back the client if
+# ``auth'' or ``cbcp'' callback is enabled (see ``set callback'').
+# A ``*'' specifies that the client must specify the number.
+#
+#
+##################################################
+
+# Authname Authkey Peer's IP address Label Callback
+
+oscar OurSecretKey 192.2.18.34
+BigBird X4dWg9327 192.2.18.33/32
+fred * * fred
+subnet * 192.2.18.35-192.2.18.70 subnet
+admin * * * *
+homeworker * * * 1234567
diff --git a/share/examples/ppp/ppp.secret.span-isp b/share/examples/ppp/ppp.secret.span-isp
new file mode 100644
index 000000000000..480933753e84
--- /dev/null
+++ b/share/examples/ppp/ppp.secret.span-isp
@@ -0,0 +1,5 @@
+
+# Refer to ppp.conf.span-isp for a description of what this file is for.
+# This file is only required on the Receiver machine.
+
+vpnname vpnkey
diff --git a/share/examples/ppp/ppp.secret.span-isp.working b/share/examples/ppp/ppp.secret.span-isp.working
new file mode 100644
index 000000000000..8b76d1560812
--- /dev/null
+++ b/share/examples/ppp/ppp.secret.span-isp.working
@@ -0,0 +1,8 @@
+
+# This is a working example of ppp.secret.span-isp that uses ppp connections
+# to the same machine through 3 null-modem serial cables.
+
+isp1name isp1key
+isp2name isp2key
+isp3name isp3key
+vpnname vpnkey
diff --git a/share/examples/printing/diablo-if-net b/share/examples/printing/diablo-if-net
new file mode 100644
index 000000000000..b2ba028f2343
--- /dev/null
+++ b/share/examples/printing/diablo-if-net
@@ -0,0 +1,7 @@
+#!/bin/sh
+#
+# diablo-if-net - Text filter for Diablo printer `scrivener' listening
+# on port 5100. Installed in /usr/local/libexec/diablo-if-net
+#
+
+exec /usr/libexec/lpr/lpf "$@" | /usr/local/libexec/netprint scrivener 5100
diff --git a/share/examples/printing/hpdf b/share/examples/printing/hpdf
new file mode 100644
index 000000000000..d03c3ac70dfd
--- /dev/null
+++ b/share/examples/printing/hpdf
@@ -0,0 +1,59 @@
+#!/bin/sh
+#
+# hpdf - Print DVI data on HP/PCL printer
+# Installed in /usr/local/libexec/hpdf
+
+PATH=/usr/local/bin:$PATH; export PATH
+
+#
+# Define a function to clean up our temporary files. These exist
+# in the current directory, which will be the spooling directory
+# for the printer.
+#
+cleanup() {
+ rm -f hpdf$$.dvi
+}
+
+#
+# Define a function to handle fatal errors: print the given message
+# and exit 2. Exiting with 2 tells LPD to do not try to reprint the
+# job.
+#
+fatal() {
+ echo "$@" 1>&2
+ cleanup
+ exit 2
+}
+
+#
+# If user removes the job, LPD will send SIGINT, so trap SIGINT
+# (and a few other signals) to clean up after ourselves.
+#
+trap cleanup 1 2 15
+
+#
+# Make sure we are not colliding with any existing files.
+#
+cleanup
+
+#
+# Link the DVI input file to standard input (the file to print).
+#
+ln -s /dev/fd/0 hpdf$$.dvi || fatal "Cannot symlink /dev/fd/0"
+
+#
+# Make LF = CR+LF
+#
+printf "\033&k2G" || fatal "Cannot initialize printer"
+
+#
+# Convert and print. Return value from dvilj2p does not seem to be
+# reliable, so we ignore it.
+#
+dvilj2p -M1 -q -e- dfhp$$.dvi
+
+#
+# Clean up and exit
+#
+cleanup
+exit 0
diff --git a/share/examples/printing/hpif b/share/examples/printing/hpif
new file mode 100644
index 000000000000..69f1f34c55fd
--- /dev/null
+++ b/share/examples/printing/hpif
@@ -0,0 +1,11 @@
+#!/bin/sh
+#
+# hpif - Simple text input filter for lpd for HP-PCL based printers
+# Installed in /usr/local/libexec/hpif
+#
+# Simply copies stdin to stdout. Ignores all filter arguments.
+# Tells printer to treat LF as CR+LF. Writes a form feed character
+# after printing job.
+
+printf "\033&k2G" && cat && printf "\f" && exit 0
+exit 2
diff --git a/share/examples/printing/hpof b/share/examples/printing/hpof
new file mode 100644
index 000000000000..691b07f95d16
--- /dev/null
+++ b/share/examples/printing/hpof
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# hpof - Output filter for Hewlett Packard PCL-compatible printers
+# Installed in /usr/local/libexec/hpof
+
+
+printf "\033&k2G" || exit 2
+exec /usr/libexec/lpr/lpf
diff --git a/share/examples/printing/hprf b/share/examples/printing/hprf
new file mode 100644
index 000000000000..37ad583fd9e1
--- /dev/null
+++ b/share/examples/printing/hprf
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# hprf - FORTRAN text filter for LaserJet 3si:
+# Installed in /usr/local/libexec/hprf
+#
+
+printf "\033&k2G" && fpr && printf "\f" && exit 0
+exit 2
diff --git a/share/examples/printing/hpvf b/share/examples/printing/hpvf
new file mode 100644
index 000000000000..de892ef77008
--- /dev/null
+++ b/share/examples/printing/hpvf
@@ -0,0 +1,9 @@
+#!/bin/sh
+#
+#
+# hpvf - Convert GIF files into HP/PCL, then print
+# Installed in /usr/local/libexec/hpvf
+
+giftopnm | ppmtopgm | pgmtopbm | pbmtolj -resolution 300 \
+ && exit 0 \
+ || exit 2
diff --git a/share/examples/printing/if-simple b/share/examples/printing/if-simple
new file mode 100644
index 000000000000..7a5bf97ab38f
--- /dev/null
+++ b/share/examples/printing/if-simple
@@ -0,0 +1,9 @@
+#!/bin/sh
+#
+# if-simple - Simple text input filter for lpd
+# Installed in /usr/local/libexec/if-simple
+#
+# Simply copies stdin to stdout. Ignores all filter arguments.
+
+/bin/cat && exit 0
+exit 2
diff --git a/share/examples/printing/if-simpleX b/share/examples/printing/if-simpleX
new file mode 100644
index 000000000000..c14b4a25d12b
--- /dev/null
+++ b/share/examples/printing/if-simpleX
@@ -0,0 +1,10 @@
+#!/bin/sh
+#
+# if-simple - Simple text input filter for lpd
+# Installed in /usr/local/libexec/if-simple
+#
+# Simply copies stdin to stdout. Ignores all filter arguments.
+# Writes a form feed character (\f) after printing job.
+
+/bin/cat && printf "\f" && exit 0
+exit 2
diff --git a/share/examples/printing/ifhp b/share/examples/printing/ifhp
new file mode 100644
index 000000000000..ace0fab4214b
--- /dev/null
+++ b/share/examples/printing/ifhp
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# ifhp - Print Ghostscript-simulated PostScript on a DesJet 500
+# Installed in /usr/local/libexec/hpif
+
+#
+# Treat LF as CR+LF:
+#
+printf "\033&k2G" || exit 2
+
+#
+# Read first two characters of the file
+#
+read first_line
+first_two_chars=`expr "$first_line" : '\(..\)'`
+
+if [ "$first_two_chars" = "%!" ]; then
+ #
+ # It is PostScript; use Ghostscript to scan-convert and print it
+ #
+ /usr/local/bin/gs -dSAFER -dNOPAUSE -q -sDEVICE=djet500 -sOutputFile=- - \
+ && exit 0
+
+else
+ #
+ # Plain text or HP/PCL, so just print it directly; print a form
+ # at the end to eject the last page.
+ #
+ echo "$first_line" && cat && printf "\f" && exit 0
+fi
+
+exit 2
diff --git a/share/examples/printing/make-ps-header b/share/examples/printing/make-ps-header
new file mode 100644
index 000000000000..19e38ab7c779
--- /dev/null
+++ b/share/examples/printing/make-ps-header
@@ -0,0 +1,79 @@
+#!/bin/sh
+#
+# make-ps-header - make a PostScript header page on stdout
+# Installed in /usr/local/libexec/make-ps-header
+#
+
+#
+# These are PostScript units (72 to the inch). Modify for A4 or
+# whatever size paper you are using:
+#
+page_width=612
+page_height=792
+border=72
+
+#
+# Check arguments
+#
+if [ $# -ne 3 ]; then
+ echo "Usage: `basename $0` <user> <host> <job>" 1>&2
+ exit 1
+fi
+
+#
+# Save these, mostly for readability in the PostScript, below.
+#
+user=$1
+host=$2
+job=$3
+date=`date`
+
+#
+# Send the PostScript code to stdout.
+#
+exec cat <<EOF
+%!PS
+
+%
+% Make sure we do not interfere with user's job that will follow
+%
+save
+
+%
+% Make a thick, unpleasant border around the edge of the paper.
+%
+$border $border moveto
+$page_width $border 2 mul sub 0 rlineto
+0 $page_height $border 2 mul sub rlineto
+currentscreen 3 -1 roll pop 100 3 1 roll setscreen
+$border 2 mul $page_width sub 0 rlineto closepath
+0.8 setgray 10 setlinewidth stroke 0 setgray
+
+%
+% Display user's login name, nice and large and prominent
+%
+/Helvetica-Bold findfont 64 scalefont setfont
+$page_width ($user) stringwidth pop sub 2 div $page_height 200 sub moveto
+($user) show
+
+%
+% Now show the boring particulars
+%
+/Helvetica findfont 14 scalefont setfont
+/y 200 def
+[ (Job:) (Host:) (Date:) ] {
+ 200 y moveto show /y y 18 sub def
+} forall
+
+/Helvetica-Bold findfont 14 scalefont setfont
+/y 200 def
+[ ($job) ($host) ($date) ] {
+ 270 y moveto show /y y 18 sub def
+} forall
+
+%
+% That is it
+%
+restore
+showpage
+EOF
diff --git a/share/examples/printing/netprint b/share/examples/printing/netprint
new file mode 100644
index 000000000000..9b5010cc8cc5
--- /dev/null
+++ b/share/examples/printing/netprint
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+#
+# netprint - Text filter for printer attached to network
+# Installed in /usr/local/libexec/netprint
+#
+
+$#ARGV eq 1 || die "Usage: $0 <printer-hostname> <port-number>";
+
+$printer_host = $ARGV[0];
+$printer_port = $ARGV[1];
+
+require 'sys/socket.ph';
+
+($ignore, $ignore, $protocol) = getprotobyname('tcp');
+($ignore, $ignore, $ignore, $ignore, $address)
+ = gethostbyname($printer_host);
+
+$sockaddr = pack('S n a4 x8', &AF_INET, $printer_port, $address);
+
+socket(PRINTER, &PF_INET, &SOCK_STREAM, $protocol)
+ || die "Can't create TCP/IP stream socket: $!";
+connect(PRINTER, $sockaddr) || die "Can't contact $printer_host: $!";
+while (<STDIN>) { print PRINTER; }
+exit 0;
diff --git a/share/examples/printing/psdf b/share/examples/printing/psdf
new file mode 100644
index 000000000000..e0d429b953c2
--- /dev/null
+++ b/share/examples/printing/psdf
@@ -0,0 +1,8 @@
+#!bin/sh
+#
+# psdf - DVI to PostScript printer filter
+# Installed in /usr/local/libexec/psdf
+#
+# Invoked by lpd when user runs lpr -d
+#
+exec /usr/local/bin/dvips -f | /usr/local/libexec/lprps "$@"
diff --git a/share/examples/printing/psdfX b/share/examples/printing/psdfX
new file mode 100644
index 000000000000..43bdc4100bdb
--- /dev/null
+++ b/share/examples/printing/psdfX
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# psdf - DVI to PostScript printer filter
+# Installed in /usr/local/libexec/psdf
+#
+# Invoked by lpd when user runs lpr -d
+#
+
+orig_args="$@"
+
+fail() {
+ echo "$@" 1>&2
+ exit 2
+}
+
+while getopts "x:y:n:h:" option; do
+ case $option in
+ x|y) ;; # Ignore
+ n) login=$OPTARG ;;
+ h) host=$OPTARG ;;
+ *) echo "LPD started `basename $0` wrong." 1>&2
+ exit 2
+ ;;
+ esac
+done
+
+[ "$login" ] || fail "No login name"
+[ "$host" ] || fail "No host name"
+
+( /u/kelly/freebsd/printing/filters/make-ps-header $login $host "DVI File"
+ /usr/local/bin/dvips -f ) | eval /usr/local/libexec/lprps $orig_args
diff --git a/share/examples/printing/psif b/share/examples/printing/psif
new file mode 100644
index 000000000000..1a816f64888b
--- /dev/null
+++ b/share/examples/printing/psif
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# psif - Print PostScript or plain text on a PostScript printer
+# Script version; NOT the version that comes with lprps
+# Installed in /usr/local/libexec/psif
+#
+
+read first_line
+first_two_chars=`expr "$first_line" : '\(..\)'`
+
+if [ "$first_two_chars" = "%!" ]; then
+ #
+ # PostScript job, print it.
+ #
+ echo "$first_line" && cat && printf "\004" && exit 0
+ exit 2
+else
+ #
+ # Plain text, convert it, then print it.
+ #
+ ( echo "$first_line"; cat ) | /usr/local/bin/textps && printf "\004" && exit 0
+ exit 2
+fi
diff --git a/share/examples/printing/pstf b/share/examples/printing/pstf
new file mode 100644
index 000000000000..308adc19e2ab
--- /dev/null
+++ b/share/examples/printing/pstf
@@ -0,0 +1,6 @@
+#!/bin/sh
+#
+# pstf - Convert groff's troff data into PS, then print.
+# Installed in /usr/local/libexec/pstf
+#
+exec grops | /usr/local/libexec/lprps "$@"
diff --git a/share/examples/printing/pstfX b/share/examples/printing/pstfX
new file mode 100644
index 000000000000..1af7134223c2
--- /dev/null
+++ b/share/examples/printing/pstfX
@@ -0,0 +1,6 @@
+#!/bin/sh
+#
+# pstf - Convert groff's troff data into PS, then print.
+# Installed in /usr/local/libexec/pstf
+#
+exec grops
diff --git a/share/examples/scsi_target/Makefile b/share/examples/scsi_target/Makefile
new file mode 100644
index 000000000000..39950b8c0ac1
--- /dev/null
+++ b/share/examples/scsi_target/Makefile
@@ -0,0 +1,11 @@
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/${PROG}
+PROG= scsi_target
+SRCS= scsi_target.h scsi_target.c scsi_cmds.c
+DPADD= ${LIBCAM} ${LIBSBUF}
+LDADD= -lcam -lsbuf
+
+MAN= scsi_target.8
+
+.include <bsd.prog.mk>
diff --git a/share/examples/scsi_target/scsi_cmds.c b/share/examples/scsi_target/scsi_cmds.c
new file mode 100644
index 000000000000..43217a562aba
--- /dev/null
+++ b/share/examples/scsi_target/scsi_cmds.c
@@ -0,0 +1,813 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * SCSI Disk Emulator
+ *
+ * Copyright (c) 2002 Nate Lawson.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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 <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <aio.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <cam/cam.h>
+#include <cam/cam_ccb.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_targetio.h>
+#include "scsi_target.h"
+
+typedef int targ_start_func(struct ccb_accept_tio *, struct ccb_scsiio *);
+typedef void targ_done_func(struct ccb_accept_tio *, struct ccb_scsiio *,
+ io_ops);
+#ifndef REPORT_LUNS
+#define REPORT_LUNS 0xa0
+#endif
+
+struct targ_cdb_handlers {
+ u_int8_t cmd;
+ targ_start_func *start;
+ targ_done_func *done;
+#define ILLEGAL_CDB 0xFF
+};
+
+static targ_start_func tcmd_inquiry;
+static targ_start_func tcmd_req_sense;
+static targ_start_func tcmd_rd_cap;
+#ifdef READ_16
+static targ_start_func tcmd_rd_cap16;
+#endif
+static targ_start_func tcmd_rdwr;
+static targ_start_func tcmd_rdwr_decode;
+static targ_done_func tcmd_rdwr_done;
+static targ_start_func tcmd_null_ok;
+static targ_start_func tcmd_illegal_req;
+static int start_io(struct ccb_accept_tio *atio,
+ struct ccb_scsiio *ctio, int dir);
+static int init_inquiry(u_int16_t req_flags, u_int16_t sim_flags);
+static struct initiator_state *
+ tcmd_get_istate(u_int init_id);
+static void cdb_debug(u_int8_t *cdb, const char *msg, ...);
+
+static struct targ_cdb_handlers cdb_handlers[] = {
+ { READ_10, tcmd_rdwr, tcmd_rdwr_done },
+ { WRITE_10, tcmd_rdwr, tcmd_rdwr_done },
+ { READ_6, tcmd_rdwr, tcmd_rdwr_done },
+ { WRITE_6, tcmd_rdwr, tcmd_rdwr_done },
+ { INQUIRY, tcmd_inquiry, NULL },
+ { REQUEST_SENSE, tcmd_req_sense, NULL },
+ { READ_CAPACITY, tcmd_rd_cap, NULL },
+ { TEST_UNIT_READY, tcmd_null_ok, NULL },
+ { START_STOP_UNIT, tcmd_null_ok, NULL },
+ { SYNCHRONIZE_CACHE, tcmd_null_ok, NULL },
+ { MODE_SENSE_6, tcmd_illegal_req, NULL },
+ { MODE_SELECT_6, tcmd_illegal_req, NULL },
+ { REPORT_LUNS, tcmd_illegal_req, NULL },
+#ifdef READ_16
+ { READ_16, tcmd_rdwr, tcmd_rdwr_done },
+ { WRITE_16, tcmd_rdwr, tcmd_rdwr_done },
+ { SERVICE_ACTION_IN, tcmd_rd_cap16, NULL },
+#endif
+ { ILLEGAL_CDB, NULL, NULL }
+};
+
+static struct scsi_inquiry_data inq_data;
+static struct initiator_state istates[MAX_INITIATORS];
+extern int debug;
+extern off_t volume_size;
+extern u_int sector_size;
+extern size_t buf_size;
+
+cam_status
+tcmd_init(u_int16_t req_inq_flags, u_int16_t sim_inq_flags)
+{
+ struct initiator_state *istate;
+ int i, ret;
+
+ /* Initialize our inquiry data */
+ ret = init_inquiry(req_inq_flags, sim_inq_flags);
+ if (ret != 0)
+ return (ret);
+
+ /* We start out life with a UA to indicate power-on/reset. */
+ for (i = 0; i < MAX_INITIATORS; i++) {
+ istate = tcmd_get_istate(i);
+ bzero(istate, sizeof(*istate));
+ istate->pending_ua = UA_POWER_ON;
+ }
+
+ return (0);
+}
+
+/* Caller allocates CTIO, sets its init_id
+return 0 if done, 1 if more processing needed
+on 0, caller sets SEND_STATUS */
+int
+tcmd_handle(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, io_ops event)
+{
+ static struct targ_cdb_handlers *last_cmd;
+ struct initiator_state *istate;
+ struct atio_descr *a_descr;
+ int ret;
+
+ if (debug) {
+ warnx("tcmd_handle atio %p ctio %p atioflags %#x", atio, ctio,
+ atio->ccb_h.flags);
+ }
+ ret = 0;
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+
+ /* Do a full lookup if one-behind cache failed */
+ if (last_cmd == NULL || last_cmd->cmd != a_descr->cdb[0]) {
+ struct targ_cdb_handlers *h;
+
+ for (h = cdb_handlers; h->cmd != ILLEGAL_CDB; h++) {
+ if (a_descr->cdb[0] == h->cmd)
+ break;
+ }
+ last_cmd = h;
+ }
+
+ /* call completion and exit */
+ if (event != ATIO_WORK) {
+ if (last_cmd->done != NULL)
+ last_cmd->done(atio, ctio, event);
+ else
+ free_ccb((union ccb *)ctio);
+ return (1);
+ }
+
+ if (last_cmd->cmd == ILLEGAL_CDB) {
+ if (event != ATIO_WORK) {
+ warnx("no done func for %#x???", a_descr->cdb[0]);
+ abort();
+ }
+ /* Not found, return illegal request */
+ warnx("cdb %#x not handled", a_descr->cdb[0]);
+ tcmd_illegal_req(atio, ctio);
+ send_ccb((union ccb *)ctio, /*priority*/1);
+ return (0);
+ }
+
+ istate = tcmd_get_istate(ctio->init_id);
+ if (istate == NULL) {
+ tcmd_illegal_req(atio, ctio);
+ send_ccb((union ccb *)ctio, /*priority*/1);
+ return (0);
+ }
+
+ if (istate->pending_ca == 0 && istate->pending_ua != 0 &&
+ a_descr->cdb[0] != INQUIRY) {
+ tcmd_sense(ctio->init_id, ctio, SSD_KEY_UNIT_ATTENTION,
+ 0x29, istate->pending_ua == UA_POWER_ON ? 1 : 2);
+ istate->pending_ca = CA_UNIT_ATTN;
+ if (debug) {
+ cdb_debug(a_descr->cdb, "UA active for %u: ",
+ atio->init_id);
+ }
+ send_ccb((union ccb *)ctio, /*priority*/1);
+ return (0);
+ }
+
+ /* Store current CA and UA for later */
+ istate->orig_ua = istate->pending_ua;
+ istate->orig_ca = istate->pending_ca;
+
+ /*
+ * As per SAM2, any command that occurs
+ * after a CA is reported, clears the CA. We must
+ * also clear the UA condition, if any, that caused
+ * the CA to occur assuming the UA is not for a
+ * persistent condition.
+ */
+ istate->pending_ca = CA_NONE;
+ if (istate->orig_ca == CA_UNIT_ATTN)
+ istate->pending_ua = UA_NONE;
+
+ /* If we have a valid handler, call start or completion function */
+ if (last_cmd->cmd != ILLEGAL_CDB) {
+ ret = last_cmd->start(atio, ctio);
+ /* XXX hack */
+ if (last_cmd->start != tcmd_rdwr) {
+ a_descr->init_req += ctio->dxfer_len;
+ send_ccb((union ccb *)ctio, /*priority*/1);
+ }
+ }
+
+ return (ret);
+}
+
+static struct initiator_state *
+tcmd_get_istate(u_int init_id)
+{
+ if (init_id >= MAX_INITIATORS) {
+ warnx("illegal init_id %d, max %d", init_id, MAX_INITIATORS - 1);
+ return (NULL);
+ } else {
+ return (&istates[init_id]);
+ }
+}
+
+void
+tcmd_sense(u_int init_id, struct ccb_scsiio *ctio, u_int8_t flags,
+ u_int8_t asc, u_int8_t ascq)
+{
+ struct initiator_state *istate;
+ struct scsi_sense_data_fixed *sense;
+
+ /* Set our initiator's istate */
+ istate = tcmd_get_istate(init_id);
+ if (istate == NULL)
+ return;
+ istate->pending_ca |= CA_CMD_SENSE; /* XXX set instead of or? */
+ sense = (struct scsi_sense_data_fixed *)&istate->sense_data;
+ bzero(sense, sizeof(*sense));
+ sense->error_code = SSD_CURRENT_ERROR;
+ sense->flags = flags;
+ sense->add_sense_code = asc;
+ sense->add_sense_code_qual = ascq;
+ sense->extra_len =
+ offsetof(struct scsi_sense_data_fixed, sense_key_spec[2]) -
+ offsetof(struct scsi_sense_data_fixed, extra_len);
+
+ /* Fill out the supplied CTIO */
+ if (ctio != NULL) {
+ bcopy(sense, &ctio->sense_data, sizeof(*sense));
+ ctio->sense_len = sizeof(*sense); /* XXX */
+ ctio->ccb_h.flags &= ~CAM_DIR_MASK;
+ ctio->ccb_h.flags |= CAM_DIR_NONE | CAM_SEND_SENSE |
+ CAM_SEND_STATUS;
+ ctio->dxfer_len = 0;
+ ctio->scsi_status = SCSI_STATUS_CHECK_COND;
+ }
+}
+
+void
+tcmd_ua(u_int init_id, ua_types new_ua)
+{
+ struct initiator_state *istate;
+ u_int start, end;
+
+ if (init_id == CAM_TARGET_WILDCARD) {
+ start = 0;
+ end = MAX_INITIATORS - 1;
+ } else {
+ start = end = init_id;
+ }
+
+ for (; start <= end; start++) {
+ istate = tcmd_get_istate(start);
+ if (istate == NULL)
+ break;
+ istate->pending_ua = new_ua;
+ }
+}
+
+static int
+tcmd_inquiry(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
+{
+ struct scsi_inquiry *inq;
+ struct atio_descr *a_descr;
+ struct initiator_state *istate;
+ struct scsi_sense_data_fixed *sense;
+
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+ inq = (struct scsi_inquiry *)a_descr->cdb;
+
+ if (debug)
+ cdb_debug(a_descr->cdb, "INQUIRY from %u: ", atio->init_id);
+ /*
+ * Validate the command. We don't support any VPD pages, so
+ * complain if EVPD or CMDDT is set.
+ */
+ istate = tcmd_get_istate(ctio->init_id);
+ sense = (struct scsi_sense_data_fixed *)&istate->sense_data;
+ if ((inq->byte2 & SI_EVPD) != 0) {
+ tcmd_illegal_req(atio, ctio);
+ sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD |
+ SSD_BITPTR_VALID | /*bit value*/1;
+ sense->sense_key_spec[1] = 0;
+ sense->sense_key_spec[2] =
+ offsetof(struct scsi_inquiry, byte2);
+ } else if (inq->page_code != 0) {
+ tcmd_illegal_req(atio, ctio);
+ sense->sense_key_spec[0] = SSD_SCS_VALID | SSD_FIELDPTR_CMD;
+ sense->sense_key_spec[1] = 0;
+ sense->sense_key_spec[2] =
+ offsetof(struct scsi_inquiry, page_code);
+ } else {
+ bcopy(&inq_data, ctio->data_ptr, sizeof(inq_data));
+ ctio->dxfer_len = inq_data.additional_length + 4;
+ ctio->dxfer_len = min(ctio->dxfer_len,
+ scsi_2btoul(inq->length));
+ ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
+ ctio->scsi_status = SCSI_STATUS_OK;
+ }
+ return (0);
+}
+
+/* Initialize the inquiry response structure with the requested flags */
+static int
+init_inquiry(u_int16_t req_flags, u_int16_t sim_flags)
+{
+ struct scsi_inquiry_data *inq;
+
+ inq = &inq_data;
+ bzero(inq, sizeof(*inq));
+ inq->device = T_DIRECT | (SID_QUAL_LU_CONNECTED << 5);
+#ifdef SCSI_REV_SPC
+ inq->version = SCSI_REV_SPC; /* was 2 */
+#else
+ inq->version = SCSI_REV_3; /* was 2 */
+#endif
+
+ /*
+ * XXX cpi.hba_inquiry doesn't support Addr16 so we give the
+ * user what they want if they ask for it.
+ */
+ if ((req_flags & SID_Addr16) != 0) {
+ sim_flags |= SID_Addr16;
+ warnx("Not sure SIM supports Addr16 but enabling it anyway");
+ }
+
+ /* Advertise only what the SIM can actually support */
+ req_flags &= sim_flags;
+ scsi_ulto2b(req_flags, &inq->spc2_flags);
+
+ inq->response_format = 2; /* SCSI2 Inquiry Format */
+ inq->additional_length = SHORT_INQUIRY_LENGTH -
+ offsetof(struct scsi_inquiry_data, additional_length);
+ bcopy("FreeBSD ", inq->vendor, SID_VENDOR_SIZE);
+ bcopy("Emulated Disk ", inq->product, SID_PRODUCT_SIZE);
+ bcopy("0.1 ", inq->revision, SID_REVISION_SIZE);
+ return (0);
+}
+
+static int
+tcmd_req_sense(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
+{
+ struct scsi_request_sense *rsense;
+ struct scsi_sense_data_fixed *sense;
+ struct initiator_state *istate;
+ size_t dlen;
+ struct atio_descr *a_descr;
+
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+ rsense = (struct scsi_request_sense *)a_descr->cdb;
+
+ istate = tcmd_get_istate(ctio->init_id);
+ sense = (struct scsi_sense_data_fixed *)&istate->sense_data;
+
+ if (debug) {
+ cdb_debug(a_descr->cdb, "REQ SENSE from %u: ", atio->init_id);
+ warnx("Sending sense: %#x %#x %#x", sense->flags,
+ sense->add_sense_code, sense->add_sense_code_qual);
+ }
+
+ if (istate->orig_ca == 0) {
+ tcmd_sense(ctio->init_id, NULL, SSD_KEY_NO_SENSE, 0, 0);
+ warnx("REQUEST SENSE from %u but no pending CA!",
+ ctio->init_id);
+ }
+
+ bcopy(sense, ctio->data_ptr, sizeof(struct scsi_sense_data));
+ dlen = offsetof(struct scsi_sense_data_fixed, extra_len) +
+ sense->extra_len + 1;
+ ctio->dxfer_len = min(dlen, SCSI_CDB6_LEN(rsense->length));
+ ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
+ ctio->scsi_status = SCSI_STATUS_OK;
+ return (0);
+}
+
+static int
+tcmd_rd_cap(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
+{
+ struct scsi_read_capacity_data *srp;
+ struct atio_descr *a_descr;
+ uint32_t vsize;
+
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+ srp = (struct scsi_read_capacity_data *)ctio->data_ptr;
+
+ if (volume_size > 0xffffffff)
+ vsize = 0xffffffff;
+ else
+ vsize = (uint32_t)(volume_size - 1);
+
+ if (debug) {
+ cdb_debug(a_descr->cdb, "READ CAP from %u (%u, %u): ",
+ atio->init_id, vsize, sector_size);
+ }
+
+ bzero(srp, sizeof(*srp));
+ scsi_ulto4b(vsize, srp->addr);
+ scsi_ulto4b(sector_size, srp->length);
+
+ ctio->dxfer_len = sizeof(*srp);
+ ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
+ ctio->scsi_status = SCSI_STATUS_OK;
+ return (0);
+}
+
+#ifdef READ_16
+static int
+tcmd_rd_cap16(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
+{
+ struct scsi_read_capacity_16 *scsi_cmd;
+ struct scsi_read_capacity_data_long *srp;
+ struct atio_descr *a_descr;
+
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+ scsi_cmd = (struct scsi_read_capacity_16 *)a_descr->cdb;
+ srp = (struct scsi_read_capacity_data_long *)ctio->data_ptr;
+
+ if (scsi_cmd->service_action != SRC16_SERVICE_ACTION) {
+ tcmd_illegal_req(atio, ctio);
+ return (0);
+ }
+
+ if (debug) {
+ cdb_debug(a_descr->cdb, "READ CAP16 from %u (%u, %u): ",
+ atio->init_id, volume_size - 1, sector_size);
+ }
+
+ bzero(srp, sizeof(*srp));
+ scsi_u64to8b(volume_size - 1, srp->addr);
+ scsi_ulto4b(sector_size, srp->length);
+
+ ctio->dxfer_len = sizeof(*srp);
+ ctio->ccb_h.flags |= CAM_DIR_IN | CAM_SEND_STATUS;
+ ctio->scsi_status = SCSI_STATUS_OK;
+ return (0);
+}
+#endif
+
+static int
+tcmd_rdwr(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
+{
+ struct atio_descr *a_descr;
+ struct ctio_descr *c_descr;
+ int ret;
+
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+ c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
+
+ /* Command needs to be decoded */
+ if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_BOTH) {
+ if (debug)
+ warnx("Calling rdwr_decode");
+ ret = tcmd_rdwr_decode(atio, ctio);
+ if (ret == 0) {
+ send_ccb((union ccb *)ctio, /*priority*/1);
+ return (0);
+ }
+ }
+ ctio->ccb_h.flags |= a_descr->flags;
+
+ /* Call appropriate work function */
+ if ((a_descr->flags & CAM_DIR_IN) != 0) {
+ ret = start_io(atio, ctio, CAM_DIR_IN);
+ if (debug)
+ warnx("Starting %p DIR_IN @" OFF_FMT ":%u",
+ a_descr, c_descr->offset, a_descr->targ_req);
+ } else {
+ ret = start_io(atio, ctio, CAM_DIR_OUT);
+ if (debug)
+ warnx("Starting %p DIR_OUT @" OFF_FMT ":%u",
+ a_descr, c_descr->offset, a_descr->init_req);
+ }
+
+ return (ret);
+}
+
+static int
+tcmd_rdwr_decode(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
+{
+ uint64_t blkno;
+ uint32_t count;
+ struct atio_descr *a_descr;
+ u_int8_t *cdb;
+
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+ cdb = a_descr->cdb;
+ if (debug)
+ cdb_debug(cdb, "R/W from %u: ", atio->init_id);
+
+ switch (cdb[0]) {
+ case READ_6:
+ case WRITE_6:
+ {
+ struct scsi_rw_6 *rw_6 = (struct scsi_rw_6 *)cdb;
+ blkno = scsi_3btoul(rw_6->addr);
+ count = rw_6->length;
+ break;
+ }
+ case READ_10:
+ case WRITE_10:
+ {
+ struct scsi_rw_10 *rw_10 = (struct scsi_rw_10 *)cdb;
+ blkno = scsi_4btoul(rw_10->addr);
+ count = scsi_2btoul(rw_10->length);
+ break;
+ }
+#ifdef READ_16
+ case READ_16:
+ case WRITE_16:
+ {
+ struct scsi_rw_16 *rw_16 = (struct scsi_rw_16 *)cdb;
+ blkno = scsi_8btou64(rw_16->addr);
+ count = scsi_4btoul(rw_16->length);
+ break;
+ }
+#endif
+ default:
+ tcmd_illegal_req(atio, ctio);
+ return (0);
+ }
+ if (blkno + count > volume_size) {
+ warnx("Attempt to access past end of volume");
+ tcmd_sense(ctio->init_id, ctio,
+ SSD_KEY_ILLEGAL_REQUEST, 0x21, 0);
+ return (0);
+ }
+
+ /* Get an (overall) data length and set direction */
+ a_descr->base_off = ((off_t)blkno) * sector_size;
+ a_descr->total_len = count * sector_size;
+ if (a_descr->total_len == 0) {
+ if (debug)
+ warnx("r/w 0 blocks @ blkno " OFF_FMT, blkno);
+ tcmd_null_ok(atio, ctio);
+ return (0);
+ } else if (cdb[0] == WRITE_6 || cdb[0] == WRITE_10) {
+ a_descr->flags |= CAM_DIR_OUT;
+ if (debug)
+ warnx("write %u blocks @ blkno " OFF_FMT, count, blkno);
+ } else {
+ a_descr->flags |= CAM_DIR_IN;
+ if (debug)
+ warnx("read %u blocks @ blkno " OFF_FMT, count, blkno);
+ }
+ return (1);
+}
+
+static int
+start_io(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio, int dir)
+{
+ struct atio_descr *a_descr;
+ struct ctio_descr *c_descr;
+ int ret;
+
+ /* Set up common structures */
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+ c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
+
+ if (dir == CAM_DIR_IN) {
+ c_descr->offset = a_descr->base_off + a_descr->targ_req;
+ ctio->dxfer_len = a_descr->total_len - a_descr->targ_req;
+ } else {
+ c_descr->offset = a_descr->base_off + a_descr->init_req;
+ ctio->dxfer_len = a_descr->total_len - a_descr->init_req;
+ }
+ ctio->dxfer_len = min(ctio->dxfer_len, buf_size);
+ assert(ctio->dxfer_len >= 0);
+
+ c_descr->aiocb.aio_offset = c_descr->offset;
+ c_descr->aiocb.aio_nbytes = ctio->dxfer_len;
+
+ /* If DIR_IN, start read from target, otherwise begin CTIO xfer. */
+ ret = 1;
+ if (dir == CAM_DIR_IN) {
+ if (notaio) {
+ if (debug)
+ warnx("read sync %lu @ block " OFF_FMT,
+ (unsigned long)
+ (ctio->dxfer_len / sector_size),
+ c_descr->offset / sector_size);
+ if (lseek(c_descr->aiocb.aio_fildes,
+ c_descr->aiocb.aio_offset, SEEK_SET) < 0) {
+ perror("lseek");
+ err(1, "lseek");
+ }
+ if (read(c_descr->aiocb.aio_fildes,
+ (void *)c_descr->aiocb.aio_buf,
+ ctio->dxfer_len) != ctio->dxfer_len) {
+ err(1, "read");
+ }
+ } else {
+ if (debug)
+ warnx("read async %lu @ block " OFF_FMT,
+ (unsigned long)
+ (ctio->dxfer_len / sector_size),
+ c_descr->offset / sector_size);
+ if (aio_read(&c_descr->aiocb) < 0) {
+ err(1, "aio_read"); /* XXX */
+ }
+ }
+ a_descr->targ_req += ctio->dxfer_len;
+ /* if we're done, we can mark the CCB as to send status */
+ if (a_descr->targ_req == a_descr->total_len) {
+ ctio->ccb_h.flags |= CAM_SEND_STATUS;
+ ctio->scsi_status = SCSI_STATUS_OK;
+ ret = 0;
+ }
+ if (notaio)
+ tcmd_rdwr_done(atio, ctio, AIO_DONE);
+ } else {
+ if (a_descr->targ_ack == a_descr->total_len)
+ tcmd_null_ok(atio, ctio);
+ a_descr->init_req += ctio->dxfer_len;
+ if (a_descr->init_req == a_descr->total_len &&
+ ctio->dxfer_len > 0) {
+ /*
+ * If data phase done, remove atio from workq.
+ * The completion handler will call work_atio to
+ * send the final status.
+ */
+ ret = 0;
+ }
+ send_ccb((union ccb *)ctio, /*priority*/1);
+ }
+
+ return (ret);
+}
+
+static void
+tcmd_rdwr_done(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio,
+ io_ops event)
+{
+ struct atio_descr *a_descr;
+ struct ctio_descr *c_descr;
+
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+ c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
+
+ switch (event) {
+ case AIO_DONE:
+ if (!notaio && aio_return(&c_descr->aiocb) < 0) {
+ warn("aio_return error");
+ /* XXX */
+ tcmd_sense(ctio->init_id, ctio,
+ SSD_KEY_MEDIUM_ERROR, 0, 0);
+ send_ccb((union ccb *)ctio, /*priority*/1);
+ break;
+ }
+ a_descr->targ_ack += ctio->dxfer_len;
+ if ((a_descr->flags & CAM_DIR_IN) != 0) {
+ if (debug) {
+ if (notaio)
+ warnx("sending CTIO for AIO read");
+ else
+ warnx("sending CTIO for sync read");
+ }
+ a_descr->init_req += ctio->dxfer_len;
+ send_ccb((union ccb *)ctio, /*priority*/1);
+ } else {
+ /* Use work function to send final status */
+ if (a_descr->init_req == a_descr->total_len)
+ work_atio(atio);
+ if (debug)
+ warnx("AIO done freeing CTIO");
+ free_ccb((union ccb *)ctio);
+ }
+ break;
+ case CTIO_DONE:
+ switch (ctio->ccb_h.status & CAM_STATUS_MASK) {
+ case CAM_REQ_CMP:
+ break;
+ case CAM_REQUEUE_REQ:
+ warnx("requeueing request");
+ if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
+ if (aio_write(&c_descr->aiocb) < 0) {
+ err(1, "aio_write"); /* XXX */
+ }
+ } else {
+ if (aio_read(&c_descr->aiocb) < 0) {
+ err(1, "aio_read"); /* XXX */
+ }
+ }
+ return;
+ default:
+ errx(1, "CTIO failed, status %#x", ctio->ccb_h.status);
+ }
+ a_descr->init_ack += ctio->dxfer_len;
+ if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT &&
+ ctio->dxfer_len > 0) {
+ a_descr->targ_req += ctio->dxfer_len;
+ if (notaio) {
+ if (debug)
+ warnx("write sync %lu @ block "
+ OFF_FMT, (unsigned long)
+ (ctio->dxfer_len / sector_size),
+ c_descr->offset / sector_size);
+ if (lseek(c_descr->aiocb.aio_fildes,
+ c_descr->aiocb.aio_offset, SEEK_SET) < 0) {
+ perror("lseek");
+ err(1, "lseek");
+ }
+ if (write(c_descr->aiocb.aio_fildes,
+ (void *) c_descr->aiocb.aio_buf,
+ ctio->dxfer_len) != ctio->dxfer_len) {
+ err(1, "write");
+ }
+ tcmd_rdwr_done(atio, ctio, AIO_DONE);
+ } else {
+ if (debug)
+ warnx("write async %lu @ block "
+ OFF_FMT, (unsigned long)
+ (ctio->dxfer_len / sector_size),
+ c_descr->offset / sector_size);
+ if (aio_write(&c_descr->aiocb) < 0) {
+ err(1, "aio_write"); /* XXX */
+ }
+ }
+ } else {
+ if (debug)
+ warnx("CTIO done freeing CTIO");
+ free_ccb((union ccb *)ctio);
+ }
+ break;
+ default:
+ warnx("Unknown completion code %d", event);
+ abort();
+ /* NOTREACHED */
+ }
+}
+
+/* Simple ok message used by TUR, SYNC_CACHE, etc. */
+static int
+tcmd_null_ok(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
+{
+ if (debug) {
+ struct atio_descr *a_descr;
+
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+ cdb_debug(a_descr->cdb, "Sending null ok to %u : ", atio->init_id);
+ }
+
+ ctio->dxfer_len = 0;
+ ctio->ccb_h.flags &= ~CAM_DIR_MASK;
+ ctio->ccb_h.flags |= CAM_DIR_NONE | CAM_SEND_STATUS;
+ ctio->scsi_status = SCSI_STATUS_OK;
+ return (0);
+}
+
+/* Simple illegal request message used by MODE SENSE, etc. */
+static int
+tcmd_illegal_req(struct ccb_accept_tio *atio, struct ccb_scsiio *ctio)
+{
+ if (debug) {
+ struct atio_descr *a_descr;
+
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+ cdb_debug(a_descr->cdb, "Sending ill req to %u: ", atio->init_id);
+ }
+
+ tcmd_sense(atio->init_id, ctio, SSD_KEY_ILLEGAL_REQUEST,
+ /*asc*/0x24, /*ascq*/0);
+ return (0);
+}
+
+static void
+cdb_debug(u_int8_t *cdb, const char *msg, ...)
+{
+ char msg_buf[512];
+ int len;
+ va_list ap;
+
+ va_start(ap, msg);
+ vsnprintf(msg_buf, sizeof(msg_buf), msg, ap);
+ va_end(ap);
+ len = strlen(msg_buf);
+ scsi_cdb_string(cdb, msg_buf + len, sizeof(msg_buf) - len);
+ warnx("%s", msg_buf);
+}
diff --git a/share/examples/scsi_target/scsi_target.8 b/share/examples/scsi_target/scsi_target.8
new file mode 100644
index 000000000000..f3bcfac33ee8
--- /dev/null
+++ b/share/examples/scsi_target/scsi_target.8
@@ -0,0 +1,156 @@
+.\" Copyright (c) 2002
+.\" Nate Lawson. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. 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 Nate Lawson 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.
+.\"
+.Dd November 15, 2002
+.Dt SCSI_TARGET 8
+.Os
+.Sh NAME
+.Nm scsi_target
+.Nd usermode SCSI disk emulator
+.Sh SYNOPSIS
+.Nm
+.Op Fl AdST
+.Op Fl b Ar size
+.Op Fl c Ar size
+.Op Fl s Ar size
+.Op Fl W Ar num
+.Ar bus : Ns Ar target : Ns Ar lun
+.Ar filename
+.Sh DESCRIPTION
+The
+.Nm
+utility emulates a SCSI target device using the
+.Xr targ 4
+device driver.
+It supports the basic commands of a direct access device, like
+.Xr da 4 .
+In typical operation, it opens a control device and
+enables target mode for the specified LUN.
+It then communicates with
+the SIM using CCBs exchanged via
+.Xr read 2
+and
+.Xr write 2 .
+READ and WRITE CDBs are satisfied with the specified backing store file.
+.Pp
+For performance, all backing store accesses use
+.Xr aio 4 .
+Thus,
+.Nm
+requires a kernel compiled with
+.Cd "options VFS_AIO" .
+.Pp
+Options:
+.Bl -tag -width indent
+.It Fl A
+Enable 16 addresses if supported by the SIM.
+Default is 8.
+.It Fl S
+Enable synchronous transfers if supported by the SIM.
+Default is disabled.
+.It Fl T
+Enable tagged queuing if supported by the SIM.
+Default is no tagged queuing.
+.It Fl W Cm 8 | 16 | 32
+Enable 16 or 32 bit wide transfers if supported by the SIM.
+Default is 8.
+.It Fl b Ar bufsize
+Set buffer size for transfers.
+Transfers larger than this will be split into multiple transfers.
+.It Fl c Ar sectorsize
+Set sector size for emulated volume.
+Default is 512.
+.It Fl d
+Enable debugging output in
+.Nm
+and its associated control device.
+.It Fl s Ar volsize
+Use a different size for the emulated volume.
+Must be less than or equal to the size of
+.Ar filename .
+If the number ends with a
+.Dq Li k ,
+.Dq Li m ,
+.Dq Li g ,
+.Dq Li t ,
+.Dq Li p ,
+or
+.Dq Li e ,
+the number is multiplied by 2^10 (1K), 2^20 (1M), 2^30 (1G), 2^40 (1T),
+2^50 (1P) and 2^60 (1E)
+respectively.
+.El
+.Pp
+Required arguments:
+.Bl -tag -width indent
+.It Ar bus : Ns Ar target : Ns Ar lun
+Attach to specified bus ID, target ID, and LUN.
+.It Ar filename
+File to use as a backing store.
+.El
+.Pp
+All options default to the minimal functionality of SCSI-1.
+To be safe,
+.Nm
+checks the SIM for the requested capability before enabling target mode.
+.Sh FILES
+.Bl -tag -width ".Pa /usr/share/examples/scsi_target" -compact
+.It Pa /dev/targ*
+Control devices.
+.It Pa /usr/share/examples/scsi_target
+Source directory.
+.El
+.Sh EXAMPLES
+Create a 5 megabyte backing store file.
+.Pp
+.Dl "dd if=/dev/zero of=vol size=1m count=5"
+.Pp
+Enable target mode on bus 0, target ID 1, LUN 0, using
+.Pa vol
+as the backing store for READ6/10 and WRITE6/10 commands.
+Only the first 1000 bytes of
+.Pa vol
+will be used.
+Debugging information will be output.
+16-bit wide transfers will be used if the SIM supports them.
+.Pp
+.Dl "scsi_target -d -s 1000 -W 16 0:1:0 vol"
+.Sh SEE ALSO
+.Xr scsi 4 ,
+.Xr targ 4
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+example first appeared in
+.Fx 3.0
+and was written by
+.An Justin T. Gibbs .
+It was rewritten for
+.Fx 5.0
+by
+.An Nate Lawson Aq Mt nate@root.org .
diff --git a/share/examples/scsi_target/scsi_target.c b/share/examples/scsi_target/scsi_target.c
new file mode 100644
index 000000000000..b8f3ed6a8a81
--- /dev/null
+++ b/share/examples/scsi_target/scsi_target.c
@@ -0,0 +1,986 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * SCSI Disk Emulator
+ *
+ * Copyright (c) 2002 Nate Lawson.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <err.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <aio.h>
+#include <assert.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <sys/event.h>
+#include <sys/param.h>
+#include <sys/disk.h>
+#include <cam/cam_queue.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_targetio.h>
+#include <cam/scsi/scsi_message.h>
+#include "scsi_target.h"
+
+/* Maximum amount to transfer per CTIO */
+#define MAX_XFER MAXPHYS
+/* Maximum number of allocated CTIOs */
+#define MAX_CTIOS 64
+/* Maximum sector size for emulated volume */
+#define MAX_SECTOR 32768
+
+/* Global variables */
+int debug;
+int notaio = 0;
+off_t volume_size;
+u_int sector_size;
+size_t buf_size;
+
+/* Local variables */
+static int targ_fd;
+static int kq_fd;
+static int file_fd;
+static int num_ctios;
+static struct ccb_queue pending_queue;
+static struct ccb_queue work_queue;
+static struct ioc_enable_lun ioc_enlun = {
+ CAM_BUS_WILDCARD,
+ CAM_TARGET_WILDCARD,
+ CAM_LUN_WILDCARD
+};
+
+/* Local functions */
+static void cleanup(void);
+static int init_ccbs(void);
+static void request_loop(void);
+static void handle_read(void);
+/* static int work_atio(struct ccb_accept_tio *); */
+static void queue_io(struct ccb_scsiio *);
+static int run_queue(struct ccb_accept_tio *);
+static int work_inot(struct ccb_immediate_notify *);
+static struct ccb_scsiio *
+ get_ctio(void);
+/* static void free_ccb(union ccb *); */
+static cam_status get_sim_flags(u_int16_t *);
+static void rel_simq(void);
+static void abort_all_pending(void);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ char *file_name;
+ u_int16_t req_flags, sim_flags;
+ off_t user_size;
+
+ /* Initialize */
+ debug = 0;
+ req_flags = sim_flags = 0;
+ user_size = 0;
+ targ_fd = file_fd = kq_fd = -1;
+ num_ctios = 0;
+ sector_size = SECTOR_SIZE;
+ buf_size = DFLTPHYS;
+
+ /* Prepare resource pools */
+ TAILQ_INIT(&pending_queue);
+ TAILQ_INIT(&work_queue);
+
+ while ((ch = getopt(argc, argv, "AdSTYb:c:s:W:")) != -1) {
+ switch(ch) {
+ case 'A':
+ req_flags |= SID_Addr16;
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'S':
+ req_flags |= SID_Sync;
+ break;
+ case 'T':
+ req_flags |= SID_CmdQue;
+ break;
+ case 'b':
+ buf_size = atoi(optarg);
+ if (buf_size < 256 || buf_size > MAX_XFER)
+ errx(1, "Unreasonable buf size: %s", optarg);
+ break;
+ case 'c':
+ sector_size = atoi(optarg);
+ if (sector_size < 512 || sector_size > MAX_SECTOR)
+ errx(1, "Unreasonable sector size: %s", optarg);
+ break;
+ case 's':
+ {
+ int last, shift = 0;
+
+ last = strlen(optarg) - 1;
+ if (last > 0) {
+ switch (tolower(optarg[last])) {
+ case 'e':
+ shift += 10;
+ /* FALLTHROUGH */
+ case 'p':
+ shift += 10;
+ /* FALLTHROUGH */
+ case 't':
+ shift += 10;
+ /* FALLTHROUGH */
+ case 'g':
+ shift += 10;
+ /* FALLTHROUGH */
+ case 'm':
+ shift += 10;
+ /* FALLTHROUGH */
+ case 'k':
+ shift += 10;
+ optarg[last] = 0;
+ break;
+ }
+ }
+ user_size = strtoll(optarg, (char **)NULL, /*base*/10);
+ user_size <<= shift;
+ if (user_size < 0)
+ errx(1, "Unreasonable volume size: %s", optarg);
+ break;
+ }
+ case 'W':
+ req_flags &= ~(SID_WBus16 | SID_WBus32);
+ switch (atoi(optarg)) {
+ case 8:
+ /* Leave req_flags zeroed */
+ break;
+ case 16:
+ req_flags |= SID_WBus16;
+ break;
+ case 32:
+ req_flags |= SID_WBus32;
+ break;
+ default:
+ warnx("Width %s not supported", optarg);
+ usage();
+ /* NOTREACHED */
+ }
+ break;
+ case 'Y':
+ notaio = 1;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 2)
+ usage();
+
+ sscanf(argv[0], "%u:%u:%u", &ioc_enlun.path_id, &ioc_enlun.target_id,
+ &ioc_enlun.lun_id);
+ file_name = argv[1];
+
+ if (ioc_enlun.path_id == CAM_BUS_WILDCARD ||
+ ioc_enlun.target_id == CAM_TARGET_WILDCARD ||
+ ioc_enlun.lun_id == CAM_LUN_WILDCARD) {
+ warnx("Incomplete target path specified");
+ usage();
+ /* NOTREACHED */
+ }
+ /* We don't support any vendor-specific commands */
+ ioc_enlun.grp6_len = 0;
+ ioc_enlun.grp7_len = 0;
+
+ /* Open backing store for IO */
+ file_fd = open(file_name, O_RDWR);
+ if (file_fd < 0)
+ errx(EX_NOINPUT, "open backing store file");
+
+ /* Check backing store size or use the size user gave us */
+ if (user_size == 0) {
+ struct stat st;
+
+ if (fstat(file_fd, &st) < 0)
+ err(1, "fstat file");
+#if __FreeBSD_version >= 500000
+ if ((st.st_mode & S_IFCHR) != 0) {
+ /* raw device */
+ off_t mediasize;
+ if (ioctl(file_fd, DIOCGMEDIASIZE, &mediasize) < 0)
+ err(1, "DIOCGMEDIASIZE");
+
+ /* XXX get sector size by ioctl()?? */
+ volume_size = mediasize / sector_size;
+ } else
+#endif
+ volume_size = st.st_size / sector_size;
+ } else {
+ volume_size = user_size / sector_size;
+ }
+ if (debug)
+ warnx("volume_size: %d bytes x " OFF_FMT " sectors",
+ sector_size, volume_size);
+
+ if (volume_size <= 0)
+ errx(1, "volume must be larger than %d", sector_size);
+
+ if (notaio == 0) {
+ struct aiocb aio, *aiop;
+
+ /* See if we have we have working AIO support */
+ memset(&aio, 0, sizeof(aio));
+ aio.aio_buf = malloc(sector_size);
+ if (aio.aio_buf == NULL)
+ err(1, "malloc");
+ aio.aio_fildes = file_fd;
+ aio.aio_offset = 0;
+ aio.aio_nbytes = sector_size;
+ signal(SIGSYS, SIG_IGN);
+ if (aio_read(&aio) != 0) {
+ printf("AIO support is not available- switchin to"
+ " single-threaded mode.\n");
+ notaio = 1;
+ } else {
+ if (aio_waitcomplete(&aiop, NULL) != sector_size)
+ err(1, "aio_waitcomplete");
+ assert(aiop == &aio);
+ signal(SIGSYS, SIG_DFL);
+ }
+ free((void *)aio.aio_buf);
+ if (debug && notaio == 0)
+ warnx("aio support tested ok");
+ }
+
+ targ_fd = open("/dev/targ", O_RDWR);
+ if (targ_fd < 0)
+ err(1, "/dev/targ");
+ else
+ warnx("opened /dev/targ");
+
+ /* The first three are handled by kevent() later */
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGPROF, SIG_IGN);
+ signal(SIGALRM, SIG_IGN);
+ signal(SIGSTOP, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+
+ /* Register a cleanup handler to run when exiting */
+ atexit(cleanup);
+
+ /* Enable listening on the specified LUN */
+ if (ioctl(targ_fd, TARGIOCENABLE, &ioc_enlun) != 0)
+ err(1, "TARGIOCENABLE");
+
+ /* Enable debugging if requested */
+ if (debug) {
+ if (ioctl(targ_fd, TARGIOCDEBUG, &debug) != 0)
+ warnx("TARGIOCDEBUG");
+ }
+
+ /* Set up inquiry data according to what SIM supports */
+ if (get_sim_flags(&sim_flags) != CAM_REQ_CMP)
+ errx(1, "get_sim_flags");
+
+ if (tcmd_init(req_flags, sim_flags) != 0)
+ errx(1, "Initializing tcmd subsystem failed");
+
+ /* Queue ATIOs and INOTs on descriptor */
+ if (init_ccbs() != 0)
+ errx(1, "init_ccbs failed");
+
+ if (debug)
+ warnx("main loop beginning");
+
+ request_loop();
+
+ exit(0);
+}
+
+static void
+cleanup()
+{
+ struct ccb_hdr *ccb_h;
+
+ if (debug) {
+ warnx("cleanup called");
+ debug = 0;
+ ioctl(targ_fd, TARGIOCDEBUG, &debug);
+ }
+ ioctl(targ_fd, TARGIOCDISABLE, NULL);
+ close(targ_fd);
+
+ while ((ccb_h = TAILQ_FIRST(&pending_queue)) != NULL) {
+ TAILQ_REMOVE(&pending_queue, ccb_h, periph_links.tqe);
+ free_ccb((union ccb *)ccb_h);
+ }
+ while ((ccb_h = TAILQ_FIRST(&work_queue)) != NULL) {
+ TAILQ_REMOVE(&work_queue, ccb_h, periph_links.tqe);
+ free_ccb((union ccb *)ccb_h);
+ }
+
+ if (kq_fd != -1)
+ close(kq_fd);
+}
+
+/* Allocate ATIOs/INOTs and queue on HBA */
+static int
+init_ccbs()
+{
+ int i;
+
+ for (i = 0; i < MAX_INITIATORS; i++) {
+ struct ccb_accept_tio *atio;
+ struct atio_descr *a_descr;
+ struct ccb_immediate_notify *inot;
+
+ atio = (struct ccb_accept_tio *)malloc(sizeof(*atio));
+ if (atio == NULL) {
+ warn("malloc ATIO");
+ return (-1);
+ }
+ a_descr = (struct atio_descr *)malloc(sizeof(*a_descr));
+ if (a_descr == NULL) {
+ free(atio);
+ warn("malloc atio_descr");
+ return (-1);
+ }
+ atio->ccb_h.func_code = XPT_ACCEPT_TARGET_IO;
+ atio->ccb_h.targ_descr = a_descr;
+ send_ccb((union ccb *)atio, /*priority*/1);
+
+ inot = (struct ccb_immediate_notify *)malloc(sizeof(*inot));
+ if (inot == NULL) {
+ warn("malloc INOT");
+ return (-1);
+ }
+ inot->ccb_h.func_code = XPT_IMMEDIATE_NOTIFY;
+ send_ccb((union ccb *)inot, /*priority*/1);
+ }
+
+ return (0);
+}
+
+static void
+request_loop()
+{
+ struct kevent events[MAX_EVENTS];
+ struct timespec ts, *tptr;
+ int quit;
+
+ /* Register kqueue for event notification */
+ if ((kq_fd = kqueue()) < 0)
+ err(1, "init kqueue");
+
+ /* Set up some default events */
+ EV_SET(&events[0], SIGHUP, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
+ EV_SET(&events[1], SIGINT, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
+ EV_SET(&events[2], SIGTERM, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0, 0, 0);
+ EV_SET(&events[3], targ_fd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
+ if (kevent(kq_fd, events, 4, NULL, 0, NULL) < 0)
+ err(1, "kevent signal registration");
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ tptr = NULL;
+ quit = 0;
+
+ /* Loop until user signal */
+ while (quit == 0) {
+ int retval, i, oo;
+ struct ccb_hdr *ccb_h;
+
+ /* Check for the next signal, read ready, or AIO completion */
+ retval = kevent(kq_fd, NULL, 0, events, MAX_EVENTS, tptr);
+ if (retval < 0) {
+ if (errno == EINTR) {
+ if (debug)
+ warnx("EINTR, looping");
+ continue;
+ }
+ else {
+ err(1, "kevent failed");
+ }
+ } else if (retval > MAX_EVENTS) {
+ errx(1, "kevent returned more events than allocated?");
+ }
+
+ /* Process all received events. */
+ for (oo = i = 0; i < retval; i++) {
+ if ((events[i].flags & EV_ERROR) != 0)
+ errx(1, "kevent registration failed");
+
+ switch (events[i].filter) {
+ case EVFILT_READ:
+ if (debug)
+ warnx("read ready");
+ handle_read();
+ break;
+ case EVFILT_AIO:
+ {
+ struct ccb_scsiio *ctio;
+ struct ctio_descr *c_descr;
+ if (debug)
+ warnx("aio ready");
+
+ ctio = (struct ccb_scsiio *)events[i].udata;
+ c_descr = (struct ctio_descr *)
+ ctio->ccb_h.targ_descr;
+ c_descr->event = AIO_DONE;
+ /* Queue on the appropriate ATIO */
+ queue_io(ctio);
+ /* Process any queued completions. */
+ oo += run_queue(c_descr->atio);
+ break;
+ }
+ case EVFILT_SIGNAL:
+ if (debug)
+ warnx("signal ready, setting quit");
+ quit = 1;
+ break;
+ default:
+ warnx("unknown event %d", events[i].filter);
+ break;
+ }
+
+ if (debug)
+ warnx("event %d done", events[i].filter);
+ }
+
+ if (oo) {
+ tptr = &ts;
+ continue;
+ }
+
+ /* Grab the first CCB and perform one work unit. */
+ if ((ccb_h = TAILQ_FIRST(&work_queue)) != NULL) {
+ union ccb *ccb;
+
+ ccb = (union ccb *)ccb_h;
+ switch (ccb_h->func_code) {
+ case XPT_ACCEPT_TARGET_IO:
+ /* Start one more transfer. */
+ retval = work_atio(&ccb->atio);
+ break;
+ case XPT_IMMEDIATE_NOTIFY:
+ retval = work_inot(&ccb->cin1);
+ break;
+ default:
+ warnx("Unhandled ccb type %#x on workq",
+ ccb_h->func_code);
+ abort();
+ /* NOTREACHED */
+ }
+
+ /* Assume work function handled the exception */
+ if ((ccb_h->status & CAM_DEV_QFRZN) != 0) {
+ if (debug) {
+ warnx("Queue frozen receiving CCB, "
+ "releasing");
+ }
+ rel_simq();
+ }
+
+ /* No more work needed for this command. */
+ if (retval == 0) {
+ TAILQ_REMOVE(&work_queue, ccb_h,
+ periph_links.tqe);
+ }
+ }
+
+ /*
+ * Poll for new events (i.e. completions) while we
+ * are processing CCBs on the work_queue. Once it's
+ * empty, use an infinite wait.
+ */
+ if (!TAILQ_EMPTY(&work_queue))
+ tptr = &ts;
+ else
+ tptr = NULL;
+ }
+}
+
+/* CCBs are ready from the kernel */
+static void
+handle_read()
+{
+ union ccb *ccb_array[MAX_INITIATORS], *ccb;
+ int ccb_count, i, oo;
+
+ ccb_count = read(targ_fd, ccb_array, sizeof(ccb_array));
+ if (ccb_count <= 0) {
+ warn("read ccb ptrs");
+ return;
+ }
+ ccb_count /= sizeof(union ccb *);
+ if (ccb_count < 1) {
+ warnx("truncated read ccb ptr?");
+ return;
+ }
+
+ for (i = 0; i < ccb_count; i++) {
+ ccb = ccb_array[i];
+ TAILQ_REMOVE(&pending_queue, &ccb->ccb_h, periph_links.tqe);
+
+ switch (ccb->ccb_h.func_code) {
+ case XPT_ACCEPT_TARGET_IO:
+ {
+ struct ccb_accept_tio *atio;
+ struct atio_descr *a_descr;
+
+ /* Initialize ATIO descr for this transaction */
+ atio = &ccb->atio;
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+ bzero(a_descr, sizeof(*a_descr));
+ TAILQ_INIT(&a_descr->cmplt_io);
+ a_descr->flags = atio->ccb_h.flags &
+ (CAM_DIS_DISCONNECT | CAM_TAG_ACTION_VALID);
+ /* XXX add a_descr->priority */
+ if ((atio->ccb_h.flags & CAM_CDB_POINTER) == 0)
+ a_descr->cdb = atio->cdb_io.cdb_bytes;
+ else
+ a_descr->cdb = atio->cdb_io.cdb_ptr;
+
+ /* ATIOs are processed in FIFO order */
+ TAILQ_INSERT_TAIL(&work_queue, &ccb->ccb_h,
+ periph_links.tqe);
+ break;
+ }
+ case XPT_CONT_TARGET_IO:
+ {
+ struct ccb_scsiio *ctio;
+ struct ctio_descr *c_descr;
+
+ ctio = &ccb->ctio;
+ c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
+ c_descr->event = CTIO_DONE;
+ /* Queue on the appropriate ATIO */
+ queue_io(ctio);
+ /* Process any queued completions. */
+ oo += run_queue(c_descr->atio);
+ break;
+ }
+ case XPT_IMMEDIATE_NOTIFY:
+ /* INOTs are handled with priority */
+ TAILQ_INSERT_HEAD(&work_queue, &ccb->ccb_h,
+ periph_links.tqe);
+ break;
+ default:
+ warnx("Unhandled ccb type %#x in handle_read",
+ ccb->ccb_h.func_code);
+ break;
+ }
+ }
+}
+
+/* Process an ATIO CCB from the kernel */
+int
+work_atio(struct ccb_accept_tio *atio)
+{
+ struct ccb_scsiio *ctio;
+ struct atio_descr *a_descr;
+ struct ctio_descr *c_descr;
+ cam_status status;
+ int ret;
+
+ if (debug)
+ warnx("Working on ATIO %p", atio);
+
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+
+ /* Get a CTIO and initialize it according to our known parameters */
+ ctio = get_ctio();
+ if (ctio == NULL) {
+ return (1);
+ }
+ ret = 0;
+ ctio->ccb_h.flags = a_descr->flags;
+ ctio->tag_id = atio->tag_id;
+ ctio->init_id = atio->init_id;
+ /* XXX priority needs to be added to a_descr */
+ c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
+ c_descr->atio = atio;
+ if ((a_descr->flags & CAM_DIR_IN) != 0)
+ c_descr->offset = a_descr->base_off + a_descr->targ_req;
+ else if ((a_descr->flags & CAM_DIR_MASK) == CAM_DIR_OUT)
+ c_descr->offset = a_descr->base_off + a_descr->init_req;
+ else
+ c_descr->offset = a_descr->base_off;
+
+ /*
+ * Return a check condition if there was an error while
+ * receiving this ATIO.
+ */
+ if (atio->sense_len != 0) {
+ struct scsi_sense_data_fixed *sense;
+
+ if (debug) {
+ warnx("ATIO with %u bytes sense received",
+ atio->sense_len);
+ }
+ sense = (struct scsi_sense_data_fixed *)&atio->sense_data;
+ tcmd_sense(ctio->init_id, ctio, sense->flags,
+ sense->add_sense_code, sense->add_sense_code_qual);
+ send_ccb((union ccb *)ctio, /*priority*/1);
+ return (0);
+ }
+
+ status = atio->ccb_h.status & CAM_STATUS_MASK;
+ switch (status) {
+ case CAM_CDB_RECVD:
+ ret = tcmd_handle(atio, ctio, ATIO_WORK);
+ break;
+ case CAM_REQ_ABORTED:
+ warn("ATIO %p aborted", a_descr);
+ /* Requeue on HBA */
+ TAILQ_REMOVE(&work_queue, &atio->ccb_h, periph_links.tqe);
+ send_ccb((union ccb *)atio, /*priority*/1);
+ ret = 1;
+ break;
+ default:
+ warnx("ATIO completed with unhandled status %#x", status);
+ abort();
+ /* NOTREACHED */
+ break;
+ }
+
+ return (ret);
+}
+
+static void
+queue_io(struct ccb_scsiio *ctio)
+{
+ struct ccb_hdr *ccb_h;
+ struct io_queue *ioq;
+ struct ctio_descr *c_descr;
+
+ c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
+ if (c_descr->atio == NULL) {
+ errx(1, "CTIO %p has NULL ATIO", ctio);
+ }
+ ioq = &((struct atio_descr *)c_descr->atio->ccb_h.targ_descr)->cmplt_io;
+
+ if (TAILQ_EMPTY(ioq)) {
+ TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe);
+ return;
+ }
+
+ TAILQ_FOREACH_REVERSE(ccb_h, ioq, io_queue, periph_links.tqe) {
+ struct ctio_descr *curr_descr =
+ (struct ctio_descr *)ccb_h->targ_descr;
+ if (curr_descr->offset <= c_descr->offset) {
+ break;
+ }
+ }
+
+ if (ccb_h) {
+ TAILQ_INSERT_AFTER(ioq, ccb_h, &ctio->ccb_h, periph_links.tqe);
+ } else {
+ TAILQ_INSERT_HEAD(ioq, &ctio->ccb_h, periph_links.tqe);
+ }
+}
+
+/*
+ * Go through all completed AIO/CTIOs for a given ATIO and advance data
+ * counts, start continuation IO, etc.
+ */
+static int
+run_queue(struct ccb_accept_tio *atio)
+{
+ struct atio_descr *a_descr;
+ struct ccb_hdr *ccb_h;
+ int sent_status, event;
+
+ if (atio == NULL)
+ return (0);
+
+ a_descr = (struct atio_descr *)atio->ccb_h.targ_descr;
+
+ while ((ccb_h = TAILQ_FIRST(&a_descr->cmplt_io)) != NULL) {
+ struct ccb_scsiio *ctio;
+ struct ctio_descr *c_descr;
+
+ ctio = (struct ccb_scsiio *)ccb_h;
+ c_descr = (struct ctio_descr *)ctio->ccb_h.targ_descr;
+
+ if (ctio->ccb_h.status == CAM_REQ_ABORTED) {
+ TAILQ_REMOVE(&a_descr->cmplt_io, ccb_h,
+ periph_links.tqe);
+ free_ccb((union ccb *)ctio);
+ send_ccb((union ccb *)atio, /*priority*/1);
+ continue;
+ }
+
+ /* If completed item is in range, call handler */
+ if ((c_descr->event == AIO_DONE &&
+ c_descr->offset == a_descr->base_off + a_descr->targ_ack)
+ || (c_descr->event == CTIO_DONE &&
+ c_descr->offset == a_descr->base_off + a_descr->init_ack)) {
+ sent_status = (ccb_h->flags & CAM_SEND_STATUS) != 0;
+ event = c_descr->event;
+
+ TAILQ_REMOVE(&a_descr->cmplt_io, ccb_h,
+ periph_links.tqe);
+ tcmd_handle(atio, ctio, c_descr->event);
+
+ /* If entire transfer complete, send back ATIO */
+ if (sent_status != 0 && event == CTIO_DONE)
+ send_ccb((union ccb *)atio, /*priority*/1);
+ } else {
+ /* Gap in offsets so wait until later callback */
+ if (/* debug */ 1)
+ warnx("IO %p:%p out of order %s", ccb_h,
+ a_descr, c_descr->event == AIO_DONE?
+ "aio" : "ctio");
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static int
+work_inot(struct ccb_immediate_notify *inot)
+{
+ cam_status status;
+
+ if (debug)
+ warnx("Working on INOT %p", inot);
+
+ status = inot->ccb_h.status;
+ status &= CAM_STATUS_MASK;
+
+ switch (status) {
+ case CAM_SCSI_BUS_RESET:
+ tcmd_ua(CAM_TARGET_WILDCARD, UA_BUS_RESET);
+ abort_all_pending();
+ break;
+ case CAM_BDR_SENT:
+ tcmd_ua(CAM_TARGET_WILDCARD, UA_BDR);
+ abort_all_pending();
+ break;
+ case CAM_MESSAGE_RECV:
+ switch (inot->arg) {
+ case MSG_TASK_COMPLETE:
+ case MSG_INITIATOR_DET_ERR:
+ case MSG_ABORT_TASK_SET:
+ case MSG_MESSAGE_REJECT:
+ case MSG_NOOP:
+ case MSG_PARITY_ERROR:
+ case MSG_TARGET_RESET:
+ case MSG_ABORT_TASK:
+ case MSG_CLEAR_TASK_SET:
+ default:
+ warnx("INOT message %#x", inot->arg);
+ break;
+ }
+ break;
+ case CAM_REQ_ABORTED:
+ warnx("INOT %p aborted", inot);
+ break;
+ default:
+ warnx("Unhandled INOT status %#x", status);
+ break;
+ }
+
+ /* Requeue on SIM */
+ TAILQ_REMOVE(&work_queue, &inot->ccb_h, periph_links.tqe);
+ send_ccb((union ccb *)inot, /*priority*/1);
+
+ return (1);
+}
+
+void
+send_ccb(union ccb *ccb, int priority)
+{
+ if (debug)
+ warnx("sending ccb (%#x)", ccb->ccb_h.func_code);
+ ccb->ccb_h.pinfo.priority = priority;
+ if (XPT_FC_IS_QUEUED(ccb)) {
+ TAILQ_INSERT_TAIL(&pending_queue, &ccb->ccb_h,
+ periph_links.tqe);
+ }
+ if (write(targ_fd, &ccb, sizeof(ccb)) != sizeof(ccb)) {
+ warn("write ccb");
+ ccb->ccb_h.status = CAM_PROVIDE_FAIL;
+ }
+}
+
+/* Return a CTIO/descr/buf combo from the freelist or malloc one */
+static struct ccb_scsiio *
+get_ctio()
+{
+ struct ccb_scsiio *ctio;
+ struct ctio_descr *c_descr;
+ struct sigevent *se;
+
+ if (num_ctios == MAX_CTIOS) {
+ warnx("at CTIO max");
+ return (NULL);
+ }
+
+ ctio = (struct ccb_scsiio *)malloc(sizeof(*ctio));
+ if (ctio == NULL) {
+ warn("malloc CTIO");
+ return (NULL);
+ }
+ c_descr = (struct ctio_descr *)malloc(sizeof(*c_descr));
+ if (c_descr == NULL) {
+ free(ctio);
+ warn("malloc ctio_descr");
+ return (NULL);
+ }
+ c_descr->buf = malloc(buf_size);
+ if (c_descr->buf == NULL) {
+ free(c_descr);
+ free(ctio);
+ warn("malloc backing store");
+ return (NULL);
+ }
+ num_ctios++;
+
+ /* Initialize CTIO, CTIO descr, and AIO */
+ ctio->ccb_h.func_code = XPT_CONT_TARGET_IO;
+ ctio->ccb_h.retry_count = 2;
+ ctio->ccb_h.timeout = CAM_TIME_INFINITY;
+ ctio->data_ptr = c_descr->buf;
+ ctio->ccb_h.targ_descr = c_descr;
+ c_descr->aiocb.aio_buf = c_descr->buf;
+ c_descr->aiocb.aio_fildes = file_fd;
+ se = &c_descr->aiocb.aio_sigevent;
+ se->sigev_notify = SIGEV_KEVENT;
+ se->sigev_notify_kqueue = kq_fd;
+ se->sigev_value.sival_ptr = ctio;
+
+ return (ctio);
+}
+
+void
+free_ccb(union ccb *ccb)
+{
+ switch (ccb->ccb_h.func_code) {
+ case XPT_CONT_TARGET_IO:
+ {
+ struct ctio_descr *c_descr;
+
+ c_descr = (struct ctio_descr *)ccb->ccb_h.targ_descr;
+ free(c_descr->buf);
+ num_ctios--;
+ /* FALLTHROUGH */
+ }
+ case XPT_ACCEPT_TARGET_IO:
+ free(ccb->ccb_h.targ_descr);
+ /* FALLTHROUGH */
+ case XPT_IMMEDIATE_NOTIFY:
+ default:
+ free(ccb);
+ break;
+ }
+}
+
+static cam_status
+get_sim_flags(u_int16_t *flags)
+{
+ struct ccb_pathinq cpi;
+ cam_status status;
+
+ /* Find SIM capabilities */
+ bzero(&cpi, sizeof(cpi));
+ cpi.ccb_h.func_code = XPT_PATH_INQ;
+ send_ccb((union ccb *)&cpi, /*priority*/1);
+ status = cpi.ccb_h.status & CAM_STATUS_MASK;
+ if (status != CAM_REQ_CMP) {
+ fprintf(stderr, "CPI failed, status %#x\n", status);
+ return (status);
+ }
+
+ /* Can only enable on controllers that support target mode */
+ if ((cpi.target_sprt & PIT_PROCESSOR) == 0) {
+ fprintf(stderr, "HBA does not support target mode\n");
+ status = CAM_PATH_INVALID;
+ return (status);
+ }
+
+ *flags = cpi.hba_inquiry;
+ return (status);
+}
+
+static void
+rel_simq()
+{
+ struct ccb_relsim crs;
+
+ bzero(&crs, sizeof(crs));
+ crs.ccb_h.func_code = XPT_REL_SIMQ;
+ crs.release_flags = RELSIM_RELEASE_AFTER_QEMPTY;
+ crs.openings = 0;
+ crs.release_timeout = 0;
+ crs.qfrozen_cnt = 0;
+ send_ccb((union ccb *)&crs, /*priority*/0);
+}
+
+/* Cancel all pending CCBs. */
+static void
+abort_all_pending()
+{
+ struct ccb_abort cab;
+ struct ccb_hdr *ccb_h;
+
+ if (debug)
+ warnx("abort_all_pending");
+
+ bzero(&cab, sizeof(cab));
+ cab.ccb_h.func_code = XPT_ABORT;
+ TAILQ_FOREACH(ccb_h, &pending_queue, periph_links.tqe) {
+ if (debug)
+ warnx("Aborting pending CCB %p\n", ccb_h);
+ cab.abort_ccb = (union ccb *)ccb_h;
+ send_ccb((union ccb *)&cab, /*priority*/1);
+ if (cab.ccb_h.status != CAM_REQ_CMP) {
+ warnx("Unable to abort CCB, status %#x\n",
+ cab.ccb_h.status);
+ }
+ }
+}
+
+static void
+usage()
+{
+ fprintf(stderr,
+ "Usage: scsi_target [-AdSTY] [-b bufsize] [-c sectorsize]\n"
+ "\t\t[-r numbufs] [-s volsize] [-W 8,16,32]\n"
+ "\t\tbus:target:lun filename\n");
+ exit(1);
+}
diff --git a/share/examples/scsi_target/scsi_target.h b/share/examples/scsi_target/scsi_target.h
new file mode 100644
index 000000000000..a873c050b7c6
--- /dev/null
+++ b/share/examples/scsi_target/scsi_target.h
@@ -0,0 +1,129 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * SCSI Target Emulator
+ *
+ * Copyright (c) 2002 Nate Lawson.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * 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.
+ */
+
+#ifndef _SCSI_TARGET_H
+#define _SCSI_TARGET_H
+
+/*
+ * Maximum number of parallel commands to accept,
+ * 1024 for Fibre Channel (SPI is 16).
+ */
+#define MAX_INITIATORS 8
+#define SECTOR_SIZE 512
+#define MAX_EVENTS (MAX_INITIATORS + 5)
+ /* kqueue for AIO, signals */
+
+/* Additional SCSI 3 defines for inquiry response */
+#define SID_Addr16 0x0100
+
+TAILQ_HEAD(io_queue, ccb_hdr);
+
+/* Offset into the private CCB area for storing our descriptor */
+#define targ_descr periph_priv.entries[1].ptr
+
+/* Descriptor attached to each ATIO */
+struct atio_descr {
+ off_t base_off; /* Base offset for ATIO */
+ uint total_len; /* Total xfer len for this ATIO */
+ uint init_req; /* Transfer count requested to/from init */
+ uint init_ack; /* Data transferred ok to/from init */
+ uint targ_req; /* Transfer count requested to/from target */
+ uint targ_ack; /* Data transferred ok to/from target */
+ int flags; /* Flags for CTIOs */
+ u_int8_t *cdb; /* Pointer to received CDB */
+ /* List of completed AIO/CTIOs */
+ struct io_queue cmplt_io;
+};
+
+typedef enum {
+ ATIO_WORK,
+ AIO_DONE,
+ CTIO_DONE
+} io_ops;
+
+/* Descriptor attached to each CTIO */
+struct ctio_descr {
+ void *buf; /* Backing store */
+ off_t offset; /* Position in transfer (for file, */
+ /* doesn't start at 0) */
+ struct aiocb aiocb; /* AIO descriptor for this CTIO */
+ struct ccb_accept_tio *atio;
+ /* ATIO we are satisfying */
+ io_ops event; /* Event that queued this CTIO */
+};
+
+typedef enum {
+ UA_NONE = 0x00,
+ UA_POWER_ON = 0x01,
+ UA_BUS_RESET = 0x02,
+ UA_BDR = 0x04
+} ua_types;
+
+typedef enum {
+ CA_NONE = 0x00,
+ CA_UNIT_ATTN = 0x01,
+ CA_CMD_SENSE = 0x02
+} ca_types;
+
+struct initiator_state {
+ ua_types orig_ua;
+ ca_types orig_ca;
+ ua_types pending_ua;
+ ca_types pending_ca;
+ struct scsi_sense_data sense_data;
+};
+
+/* Global functions */
+extern cam_status tcmd_init(u_int16_t req_inq_flags,
+ u_int16_t sim_inq_flags);
+extern int tcmd_handle(struct ccb_accept_tio *atio,
+ struct ccb_scsiio *ctio, io_ops event);
+extern void tcmd_sense(u_int init_id, struct ccb_scsiio *ctio,
+ u_int8_t flags,
+ u_int8_t asc, u_int8_t ascq);
+extern void tcmd_ua(u_int init_id, ua_types new_ua);
+extern int work_atio(struct ccb_accept_tio *atio);
+extern void send_ccb(union ccb *ccb, int priority);
+extern void free_ccb(union ccb *ccb);
+static __inline u_int min(u_int a, u_int b) { return (a < b ? a : b); }
+
+/* Global Data */
+extern int notaio;
+
+/*
+ * Compat Defines
+ */
+#if __FreeBSD_version >= 500000
+#define OFF_FMT "%ju"
+#else
+#define OFF_FMT "%llu"
+#endif
+
+#endif /* _SCSI_TARGET_H */
diff --git a/share/examples/ses/Makefile b/share/examples/ses/Makefile
new file mode 100644
index 000000000000..a7191be1e504
--- /dev/null
+++ b/share/examples/ses/Makefile
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2000 by Matthew Jacob
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions, and the following disclaimer,
+# without modification, immediately at the beginning of the file.
+# 2. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# the GNU Public License ("GPL").
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# Matthew Jacob
+# Feral Software
+# mjacob@feral.com
+#
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/ses
+UNUSED = getobjmap getnobj getobjstat
+SUBDIR = getencstat setencstat setobjstat sesd
+
+.include <bsd.subdir.mk>
diff --git a/share/examples/ses/Makefile.inc b/share/examples/ses/Makefile.inc
new file mode 100644
index 000000000000..cce490974e11
--- /dev/null
+++ b/share/examples/ses/Makefile.inc
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2000 by Matthew Jacob
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions, and the following disclaimer,
+# without modification, immediately at the beginning of the file.
+# 2. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# the GNU Public License ("GPL").
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# Matthew Jacob
+# Feral Software
+# mjacob@feral.com
+#
+
+BINDIR?= /usr/sbin
+
+CLEANFILES+= ${MAN}
+
+.SUFFIXES: .0 .8
+.0.8:
+ cat ${.IMPSRC} > ${.TARGET}
diff --git a/share/examples/ses/getencstat/Makefile b/share/examples/ses/getencstat/Makefile
new file mode 100644
index 000000000000..d406403ddb57
--- /dev/null
+++ b/share/examples/ses/getencstat/Makefile
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2000 by Matthew Jacob
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions, and the following disclaimer,
+# without modification, immediately at the beginning of the file.
+# 2. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# the GNU Public License ("GPL").
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# Matthew Jacob
+# Feral Software
+# mjacob@feral.com
+#
+
+.PATH: ${.CURDIR}/../srcs
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/ses/${PROG}
+PROG= getencstat
+SRCS= getencstat.c eltsub.c
+MAN= getencstat.8
+
+.include <bsd.prog.mk>
diff --git a/share/examples/ses/getencstat/getencstat.0 b/share/examples/ses/getencstat/getencstat.0
new file mode 100644
index 000000000000..71882d5e7d24
--- /dev/null
+++ b/share/examples/ses/getencstat/getencstat.0
@@ -0,0 +1,81 @@
+.\" Copyright (c) 2000 Matthew Jacob
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions, and the following disclaimer,
+.\" without modification, immediately at the beginning of the file.
+.\" 2. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" Alternatively, this software may be distributed under the terms of the
+.\" the GNU Public License ("GPL").
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+.\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Matthew Jacob
+.\" Feral Software
+.\" mjacob@feral.com
+.\"
+.Dd February 21, 2000
+.Dt GETENCSTAT 8
+.Os
+.Sh NAME
+.Nm getencstat
+.Nd get SCSI Environmental Services Device enclosure status
+.Sh SYNOPSIS
+.Nm
+.Op Fl v
+.Ar device
+.Op Ar device ...
+.Sh DESCRIPTION
+.Nm
+gets summary and detailed SCSI Environmental Services (or SAF-TE) device
+enclosure status.
+The overall status is printed out.
+If the overall status
+is considered okay, nothing else is printed out (unless the
+.Fl v
+option is used).
+.Pp
+A SCSI Environmental Services device enclosure may be either in the state
+of being \fBOK\fR, or in one or more of the states of \fBINFORMATIONAL\fR,
+\fBNON-CRITICAL\fR, \fBCRITICAL\fB or \fBUNRECOVERABLE\fR states.
+These
+overall states reflect a summary of the states of each object within
+such a device (such as power supplies or disk drives).
+.Pp
+With the
+.Fl v
+option, the status of all objects within the device is printed, whether
+\fBOK\fR or not.
+Along with the status of each object is the object identifier.
+.Pp
+The user may then use
+.Xr setencstat 8
+to try and clear overall device status, or may use
+.Xr setobjstat 8
+to set specific object status.
+.Sh FILES
+.Bl -tag -width /dev/sesN -compact
+.It Pa /dev/ses\fIN\fR
+SCSI Environmental Services Devices
+.El
+.Sh SEE ALSO
+.Xr ses 4 ,
+.Xr sesd 8 ,
+.Xr setencstat 8 ,
+.Xr setobjstat 8
+.Sh BUGS
diff --git a/share/examples/ses/sesd/Makefile b/share/examples/ses/sesd/Makefile
new file mode 100644
index 000000000000..593e95d79288
--- /dev/null
+++ b/share/examples/ses/sesd/Makefile
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2000 by Matthew Jacob
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions, and the following disclaimer,
+# without modification, immediately at the beginning of the file.
+# 2. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# the GNU Public License ("GPL").
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# Matthew Jacob
+# Feral Software
+# mjacob@feral.com
+#
+
+.PATH: ${.CURDIR}/../srcs
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/ses/${PROG}
+PROG= sesd
+SRCS= sesd.c eltsub.c
+MAN= sesd.8
+
+.include <bsd.prog.mk>
diff --git a/share/examples/ses/sesd/sesd.0 b/share/examples/ses/sesd/sesd.0
new file mode 100644
index 000000000000..08fd8ecb53c4
--- /dev/null
+++ b/share/examples/ses/sesd/sesd.0
@@ -0,0 +1,86 @@
+.\" Copyright (c) 2000 Matthew Jacob
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions, and the following disclaimer,
+.\" without modification, immediately at the beginning of the file.
+.\" 2. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" Alternatively, this software may be distributed under the terms of the
+.\" the GNU Public License ("GPL").
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+.\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Matthew Jacob
+.\" Feral Software
+.\" mjacob@feral.com
+.\"
+.Dd November 5, 2012
+.Dt SESD 8
+.Os
+.Sh NAME
+.Nm sesd
+.Nd monitor SCSI Environmental Services Devices
+.Sh SYNOPSIS
+.Nm
+.Op Fl c
+.Op Fl d
+.Op Fl t Ar poll-interval
+.Ar device
+.Op Ar device ...
+.Sh DESCRIPTION
+.Nm
+monitors SCSI Environmental Services (or SAF-TE) devices for changes
+in state and logs such changes to the system error logger
+(see
+.Xr syslogd 8 ) .
+At least one device must be specified.
+When no other options are supplied,
+.Nm
+detached becomes a daemon, by default waking up every 30 seconds to
+poll each device for a change in state.
+.Pp
+The following options may be used:
+.Bl -tag -width Ds
+.It Fl c
+Try to clear enclosure status after read.
+.It Fl t Ar poll-interval
+Change the interval of polling from the default 30 seconds to the number
+of seconds specified.
+.It Fl d
+Instead of detaching and becoming a daemon, stay attached to the
+controlling terminal and log changes there as well as via the system
+logger.
+.El
+.Pp
+The user may then use
+.Xr getencstat 8
+to get more detailed information about the state of the over enclosure device
+or objects within the enclosure device.
+.Sh FILES
+.Bl -tag -width /dev/sesN -compact
+.It Pa /dev/ses\fIN\fR
+SCSI Environmental Services Devices
+.El
+.Sh SEE ALSO
+.Xr ses 4 ,
+.Xr getencstat 8 ,
+.Xr setencstat 8 ,
+.Xr setobjstat 8 ,
+.Xr syslogd 8
+.Sh BUGS
+This is something of a toy, but it is better than nothing.
diff --git a/share/examples/ses/setencstat/Makefile b/share/examples/ses/setencstat/Makefile
new file mode 100644
index 000000000000..a108d6b17ad5
--- /dev/null
+++ b/share/examples/ses/setencstat/Makefile
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2000 by Matthew Jacob
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions, and the following disclaimer,
+# without modification, immediately at the beginning of the file.
+# 2. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# the GNU Public License ("GPL").
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# Matthew Jacob
+# Feral Software
+# mjacob@feral.com
+#
+
+.PATH: ${.CURDIR}/../srcs
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/ses/${PROG}
+PROG= setencstat
+SRCS= setencstat.c eltsub.c
+MAN= setencstat.8
+
+.include <bsd.prog.mk>
diff --git a/share/examples/ses/setencstat/setencstat.0 b/share/examples/ses/setencstat/setencstat.0
new file mode 100644
index 000000000000..1b40b35d6dd0
--- /dev/null
+++ b/share/examples/ses/setencstat/setencstat.0
@@ -0,0 +1,71 @@
+.\" Copyright (c) 2000 Matthew Jacob
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions, and the following disclaimer,
+.\" without modification, immediately at the beginning of the file.
+.\" 2. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" Alternatively, this software may be distributed under the terms of the
+.\" the GNU Public License ("GPL").
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+.\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Matthew Jacob
+.\" Feral Software
+.\" mjacob@feral.com
+.\"
+.Dd February 21, 2000
+.Dt SETENCSTAT 8
+.Os
+.Sh NAME
+.Nm setencstat
+.Nd set SCSI Environmental Services Device enclosure status
+.Sh SYNOPSIS
+.Nm
+.Ar device enclosure_status
+.Sh DESCRIPTION
+.Nm
+sets summary status for a SCSI Environmental Services (or SAF-TE) device.
+The enclosure status argument may take on the values:
+.Bl -tag -width Ds
+.It 0
+Set the status to an \fBOK\fR state.
+.It 1
+Set the status to an \fBUNRECOVERABLE\fR state.
+.It 2
+Set the status to an \fBCRITICAL\fR state.
+.It 4
+Set the status to an \fBNON-CRITICAL\fR state.
+.It 8
+Set the status to an \fBINFORMATIONAL\fR state.
+.El
+.Pp
+All the non-zero options may be combined.
+.Pp
+Note that devices may simply and silently ignore the setting of these values.
+.Sh FILES
+.Bl -tag -width /dev/sesN -compact
+.It Pa /dev/ses\fIN\fR
+SCSI Environmental Services Devices
+.El
+.Sh SEE ALSO
+.Xr ses 4 ,
+.Xr getencstat 8 ,
+.Xr sesd 8 ,
+.Xr setobjstat 8
+.Sh BUGS
diff --git a/share/examples/ses/setobjstat/Makefile b/share/examples/ses/setobjstat/Makefile
new file mode 100644
index 000000000000..e34f23e74486
--- /dev/null
+++ b/share/examples/ses/setobjstat/Makefile
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2000 by Matthew Jacob
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions, and the following disclaimer,
+# without modification, immediately at the beginning of the file.
+# 2. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# the GNU Public License ("GPL").
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# Matthew Jacob
+# Feral Software
+# mjacob@feral.com
+#
+
+.PATH: ${.CURDIR}/../srcs
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/ses/${PROG}
+PROG= setobjstat
+SRCS= setobjstat.c eltsub.c
+MAN= setobjstat.8
+
+.include <bsd.prog.mk>
diff --git a/share/examples/ses/setobjstat/setobjstat.0 b/share/examples/ses/setobjstat/setobjstat.0
new file mode 100644
index 000000000000..74db543e2a7d
--- /dev/null
+++ b/share/examples/ses/setobjstat/setobjstat.0
@@ -0,0 +1,68 @@
+.\" Copyright (c) 2000 Matthew Jacob
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions, and the following disclaimer,
+.\" without modification, immediately at the beginning of the file.
+.\" 2. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" Alternatively, this software may be distributed under the terms of the
+.\" the GNU Public License ("GPL").
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+.\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" Matthew Jacob
+.\" Feral Software
+.\" mjacob@feral.com
+.\"
+.Dd February 21, 2000
+.Dt SETOBJSTAT 8
+.Os
+.Sh NAME
+.Nm setobjstat
+.Nd set SCSI Environmental Services Device object status
+.Sh SYNOPSIS
+.Nm
+.Ar device objectid stat0 stat1 stat2 stat3
+.Sh DESCRIPTION
+.Nm
+sets the object status for a SCSI Environmental Services (or SAF-TE) device.
+The
+.Ar objectid
+argument may be determined by running
+.Xr getencstat 8 .
+.Pp
+The status fields are partially common (first byte only, which must
+have a value of 0x80 contained in it), but otherwise quite device
+specific.
+A complete discussion of the possible values is impractical
+here.
+Please refer to the ANSI SCSI specification (available on
+the FTP site ftp.t10.org).
+.Pp
+Note that devices may simply and silently ignore the setting of these values.
+.Sh FILES
+.Bl -tag -width /dev/sesN -compact
+.It Pa /dev/ses\fIN\fR
+SCSI Environmental Services Devices
+.El
+.Sh SEE ALSO
+.Xr ses 4 ,
+.Xr getencstat 8 ,
+.Xr sesd 8 ,
+.Xr setencstat 8
+.Sh BUGS
diff --git a/share/examples/ses/srcs/chpmon.c b/share/examples/ses/srcs/chpmon.c
new file mode 100644
index 000000000000..40574e16cf0f
--- /dev/null
+++ b/share/examples/ses/srcs/chpmon.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include "ses.h"
+
+/*
+ * Continuously monitor all named SES devices
+ * and turn all but INFO enclosure status
+ * values into CRITICAL enclosure status.
+ */
+#define BADSTAT \
+ (SES_ENCSTAT_UNRECOV|SES_ENCSTAT_CRITICAL|SES_ENCSTAT_NONCRITICAL)
+int
+main(int a, char **v)
+{
+ int fd, delay, dev;
+ ses_encstat stat, *carray;
+
+ if (a < 3) {
+ fprintf(stderr, "usage: %s polling-interval device "
+ "[ device ... ]\n", *v);
+ return (1);
+ }
+ delay = atoi(v[1]);
+ carray = malloc(a);
+ if (carray == NULL) {
+ perror("malloc");
+ return (1);
+ }
+ bzero((void *)carray, a);
+
+ for (;;) {
+ for (dev = 2; dev < a; dev++) {
+ fd = open(v[dev], O_RDWR);
+ if (fd < 0) {
+ perror(v[dev]);
+ continue;
+ }
+ /*
+ * First clear any enclosure status, in case it is
+ * a latched status.
+ */
+ stat = 0;
+ if (ioctl(fd, SESIOC_SETENCSTAT, (caddr_t) &stat) < 0) {
+ fprintf(stderr, "%s: SESIOC_SETENCSTAT1: %s\n",
+ v[dev], strerror(errno));
+ (void) close(fd);
+ continue;
+ }
+ /*
+ * Now get the actual current enclosure status.
+ */
+ if (ioctl(fd, SESIOC_GETENCSTAT, (caddr_t) &stat) < 0) {
+ fprintf(stderr, "%s: SESIOC_GETENCSTAT: %s\n",
+ v[dev], strerror(errno));
+ (void) close(fd);
+ continue;
+ }
+
+ if ((stat & BADSTAT) == 0) {
+ if (carray[dev]) {
+ fprintf(stdout, "%s: Clearing CRITICAL "
+ "condition\n", v[dev]);
+ carray[dev] = 0;
+ }
+ (void) close(fd);
+ continue;
+ }
+ carray[dev] = 1;
+ fprintf(stdout, "%s: Setting CRITICAL from:", v[dev]);
+ if (stat & SES_ENCSTAT_UNRECOV)
+ fprintf(stdout, " UNRECOVERABLE");
+
+ if (stat & SES_ENCSTAT_CRITICAL)
+ fprintf(stdout, " CRITICAL");
+
+ if (stat & SES_ENCSTAT_NONCRITICAL)
+ fprintf(stdout, " NONCRITICAL");
+ putchar('\n');
+ stat = SES_ENCSTAT_CRITICAL;
+ if (ioctl(fd, SESIOC_SETENCSTAT, (caddr_t) &stat) < 0) {
+ fprintf(stderr, "%s: SESIOC_SETENCSTAT 2: %s\n",
+ v[dev], strerror(errno));
+ }
+ (void) close(fd);
+ }
+ sleep(delay);
+ }
+ /* NOTREACHED */
+}
diff --git a/share/examples/ses/srcs/eltsub.c b/share/examples/ses/srcs/eltsub.c
new file mode 100644
index 000000000000..4173eba4997f
--- /dev/null
+++ b/share/examples/ses/srcs/eltsub.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_enc.h>
+
+#include "eltsub.h"
+
+char *
+geteltnm(int type)
+{
+ static char rbuf[132];
+
+ switch (type) {
+ case ELMTYP_UNSPECIFIED:
+ sprintf(rbuf, "Unspecified");
+ break;
+ case ELMTYP_DEVICE:
+ sprintf(rbuf, "Device Slot");
+ break;
+ case ELMTYP_POWER:
+ sprintf(rbuf, "Power Supply");
+ break;
+ case ELMTYP_FAN:
+ sprintf(rbuf, "Cooling");
+ break;
+ case ELMTYP_THERM:
+ sprintf(rbuf, "Temperature Sensor");
+ break;
+ case ELMTYP_DOORLOCK:
+ sprintf(rbuf, "Door Lock");
+ break;
+ case ELMTYP_ALARM:
+ sprintf(rbuf, "Audible alarm");
+ break;
+ case ELMTYP_ESCC:
+ sprintf(rbuf, "Enclosure Services Controller Electronics");
+ break;
+ case ELMTYP_SCC:
+ sprintf(rbuf, "SCC Controller Electronics");
+ break;
+ case ELMTYP_NVRAM:
+ sprintf(rbuf, "Nonvolatile Cache");
+ break;
+ case ELMTYP_INV_OP_REASON:
+ sprintf(rbuf, "Invalid Operation Reason");
+ break;
+ case ELMTYP_UPS:
+ sprintf(rbuf, "Uninterruptible Power Supply");
+ break;
+ case ELMTYP_DISPLAY:
+ sprintf(rbuf, "Display");
+ break;
+ case ELMTYP_KEYPAD:
+ sprintf(rbuf, "Key Pad Entry");
+ break;
+ case ELMTYP_ENCLOSURE:
+ sprintf(rbuf, "Enclosure");
+ break;
+ case ELMTYP_SCSIXVR:
+ sprintf(rbuf, "SCSI Port/Transceiver");
+ break;
+ case ELMTYP_LANGUAGE:
+ sprintf(rbuf, "Language");
+ break;
+ case ELMTYP_COMPORT:
+ sprintf(rbuf, "Communication Port");
+ break;
+ case ELMTYP_VOM:
+ sprintf(rbuf, "Voltage Sensor");
+ break;
+ case ELMTYP_AMMETER:
+ sprintf(rbuf, "Current Sensor");
+ break;
+ case ELMTYP_SCSI_TGT:
+ sprintf(rbuf, "SCSI Target Port");
+ break;
+ case ELMTYP_SCSI_INI:
+ sprintf(rbuf, "SCSI Initiator Port");
+ break;
+ case ELMTYP_SUBENC:
+ sprintf(rbuf, "Simple Subenclosure");
+ break;
+ case ELMTYP_ARRAY_DEV:
+ sprintf(rbuf, "Array Device Slot");
+ break;
+ case ELMTYP_SAS_EXP:
+ sprintf(rbuf, "SAS Expander");
+ break;
+ case ELMTYP_SAS_CONN:
+ sprintf(rbuf, "SAS Connector");
+ break;
+ default:
+ (void) sprintf(rbuf, "<Type 0x%x>", type);
+ break;
+ }
+ return (rbuf);
+}
+
+static char *
+scode2ascii(u_char code)
+{
+ static char rbuf[32];
+ switch (code & 0xf) {
+ case SES_OBJSTAT_UNSUPPORTED:
+ sprintf(rbuf, "Unsupported");
+ break;
+ case SES_OBJSTAT_OK:
+ sprintf(rbuf, "OK");
+ break;
+ case SES_OBJSTAT_CRIT:
+ sprintf(rbuf, "Critical");
+ break;
+ case SES_OBJSTAT_NONCRIT:
+ sprintf(rbuf, "Noncritical");
+ break;
+ case SES_OBJSTAT_UNRECOV:
+ sprintf(rbuf, "Unrecoverable");
+ break;
+ case SES_OBJSTAT_NOTINSTALLED:
+ sprintf(rbuf, "Not Installed");
+ break;
+ case SES_OBJSTAT_UNKNOWN:
+ sprintf(rbuf, "Unknown");
+ break;
+ case SES_OBJSTAT_NOTAVAIL:
+ sprintf(rbuf, "Not Available");
+ break;
+ case SES_OBJSTAT_NOACCESS:
+ sprintf(rbuf, "No Access Allowed");
+ break;
+ default:
+ sprintf(rbuf, "<Status 0x%x>", code & 0xf);
+ break;
+ }
+ return (rbuf);
+}
+
+
+char *
+stat2ascii(int eletype __unused, u_char *cstat)
+{
+ static char ebuf[256], *scode;
+
+ scode = scode2ascii(cstat[0]);
+ sprintf(ebuf, "status: %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" : "",
+ cstat[0], cstat[1], cstat[2], cstat[3]);
+ return (ebuf);
+}
diff --git a/share/examples/ses/srcs/eltsub.h b/share/examples/ses/srcs/eltsub.h
new file mode 100644
index 000000000000..0623b4ac1e5c
--- /dev/null
+++ b/share/examples/ses/srcs/eltsub.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+
+char * geteltnm(int);
+char * stat2ascii(int, u_char *);
diff --git a/share/examples/ses/srcs/getencstat.c b/share/examples/ses/srcs/getencstat.c
new file mode 100644
index 000000000000..55a7a0e8edc4
--- /dev/null
+++ b/share/examples/ses/srcs/getencstat.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_enc.h>
+
+#include "eltsub.h"
+
+int
+main(int a, char **v)
+{
+ encioc_string_t stri;
+ encioc_element_t *objp;
+ encioc_elm_status_t ob;
+ encioc_elm_desc_t objd;
+ encioc_elm_devnames_t objdn;
+ int fd, nobj, f, i, verbose, quiet, errors;
+ u_char estat;
+ char str[32];
+
+ if (a < 2) {
+ fprintf(stderr, "usage: %s [ -v ] device [ device ... ]\n", *v);
+ return (1);
+ }
+ errors = quiet = verbose = 0;
+ if (strcmp(v[1], "-V") == 0) {
+ verbose = 2;
+ v++;
+ } else if (strcmp(v[1], "-v") == 0) {
+ verbose = 1;
+ v++;
+ } else if (strcmp(v[1], "-q") == 0) {
+ quiet = 1;
+ verbose = 0;
+ v++;
+ }
+ while (*++v) {
+
+ fd = open(*v, O_RDONLY);
+ if (fd < 0) {
+ perror(*v);
+ continue;
+ }
+ if (verbose > 1) {
+ stri.bufsiz = sizeof(str);
+ stri.buf = &str[0];
+ if (ioctl(fd, ENCIOC_GETENCNAME, (caddr_t) &stri) == 0)
+ printf("%s: Enclosure Name: %s\n", *v, stri.buf);
+ stri.bufsiz = sizeof(str);
+ stri.buf = &str[0];
+ if (ioctl(fd, ENCIOC_GETENCID, (caddr_t) &stri) == 0)
+ printf("%s: Enclosure ID: %s\n", *v, stri.buf);
+ }
+ if (ioctl(fd, ENCIOC_GETNELM, (caddr_t) &nobj) < 0) {
+ perror("ENCIOC_GETNELM");
+ (void) close(fd);
+ continue;
+ }
+ if (ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &estat) < 0) {
+ perror("ENCIOC_GETENCSTAT");
+ (void) close(fd);
+ continue;
+ }
+ if ((verbose == 0 || quiet == 1) && estat == 0) {
+ if (quiet == 0)
+ fprintf(stdout, "%s: Enclosure OK\n", *v);
+ (void) close(fd);
+ continue;
+ }
+ fprintf(stdout, "%s: Enclosure Status ", *v);
+ if (estat == 0) {
+ fprintf(stdout, "<OK");
+ } else {
+ errors++;
+ f = '<';
+ if (estat & SES_ENCSTAT_INFO) {
+ fprintf(stdout, "%cINFO", f);
+ f = ',';
+ }
+ if (estat & SES_ENCSTAT_NONCRITICAL) {
+ fprintf(stdout, "%cNONCRITICAL", f);
+ f = ',';
+ }
+ if (estat & SES_ENCSTAT_CRITICAL) {
+ fprintf(stdout, "%cCRITICAL", f);
+ f = ',';
+ }
+ if (estat & SES_ENCSTAT_UNRECOV) {
+ fprintf(stdout, "%cUNRECOV", f);
+ f = ',';
+ }
+ }
+ fprintf(stdout, ">\n");
+ objp = calloc(nobj, sizeof (encioc_element_t));
+ if (objp == NULL) {
+ perror("calloc");
+ (void) close(fd);
+ continue;
+ }
+ if (ioctl(fd, ENCIOC_GETELMMAP, (caddr_t) objp) < 0) {
+ perror("ENCIOC_GETELMMAP");
+ (void) close(fd);
+ continue;
+ }
+ for (i = 0; i < nobj; i++) {
+ ob.elm_idx = objp[i].elm_idx;
+ if (ioctl(fd, ENCIOC_GETELMSTAT, (caddr_t) &ob) < 0) {
+ perror("ENCIOC_GETELMSTAT");
+ (void) close(fd);
+ break;
+ }
+ bzero(&objd, sizeof(objd));
+ objd.elm_idx = objp[i].elm_idx;
+ objd.elm_desc_len = UINT16_MAX;
+ objd.elm_desc_str = calloc(UINT16_MAX, sizeof(char));
+ if (objd.elm_desc_str == NULL) {
+ perror("calloc");
+ (void) close(fd);
+ continue;
+ }
+ if (ioctl(fd, ENCIOC_GETELMDESC, (caddr_t)&objd) < 0) {
+ perror("ENCIOC_GETELMDESC");
+ (void) close(fd);
+ break;
+ }
+ bzero(&objdn, sizeof(objdn));
+ objdn.elm_idx = objp[i].elm_idx;
+ objdn.elm_names_size = 128;
+ objdn.elm_devnames = calloc(128, sizeof(char));
+ if (objdn.elm_devnames == NULL) {
+ perror("calloc");
+ (void) close(fd);
+ break;
+ }
+ /*
+ * This ioctl isn't critical and has a good chance
+ * of returning -1.
+ */
+ (void)ioctl(fd, ENCIOC_GETELMDEVNAMES, (caddr_t)&objdn);
+ fprintf(stdout, "Element 0x%x: %s", ob.elm_idx,
+ geteltnm(objp[i].elm_type));
+ fprintf(stdout, ", %s",
+ stat2ascii(objp[i].elm_type, ob.cstat));
+ if (objd.elm_desc_len > 0)
+ fprintf(stdout, ", descriptor: '%s'",
+ objd.elm_desc_str);
+ if (objdn.elm_names_len > 0)
+ fprintf(stdout, ", dev: '%s'",
+ objdn.elm_devnames);
+ fprintf(stdout, "\n");
+ free(objdn.elm_devnames);
+ }
+ free(objp);
+ (void) close(fd);
+ }
+ return (errors);
+}
diff --git a/share/examples/ses/srcs/getnobj.c b/share/examples/ses/srcs/getnobj.c
new file mode 100644
index 000000000000..6ad1bc892717
--- /dev/null
+++ b/share/examples/ses/srcs/getnobj.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_ses.h>
+
+int
+main(int argc, char **argv)
+{
+ unsigned int nobj;
+ int fd;
+
+ while (*++argv != NULL) {
+ char *name = *argv;
+ fd = open(name, O_RDONLY);
+ if (fd < 0) {
+ perror(name);
+ continue;
+ }
+ if (ioctl(fd, SESIOC_GETNOBJ, (caddr_t) &nobj) < 0) {
+ perror("SESIOC_GETNOBJ");
+ } else {
+ fprintf(stdout, "%s: %d objects\n", name, nobj);
+ }
+ close (fd);
+ }
+ return (0);
+}
diff --git a/share/examples/ses/srcs/getobjmap.c b/share/examples/ses/srcs/getobjmap.c
new file mode 100644
index 000000000000..a52484185d0e
--- /dev/null
+++ b/share/examples/ses/srcs/getobjmap.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_ses.h>
+
+#include "eltsub.h"
+
+int
+main(int a, char **v)
+{
+ ses_object *objp;
+ int nobj, fd, i;
+
+ while (*++v) {
+ fd = open(*v, O_RDONLY);
+ if (fd < 0) {
+ perror(*v);
+ continue;
+ }
+ if (ioctl(fd, SESIOC_GETNOBJ, (caddr_t) &nobj) < 0) {
+ perror("SESIOC_GETNOBJ");
+ (void) close(fd);
+ continue;
+ }
+ fprintf(stdout, "%s: %d objects\n", *v, nobj);
+ if (nobj == 0) {
+ (void) close(fd);
+ continue;
+ }
+ objp = calloc(nobj, sizeof (ses_object));
+ if (objp == NULL) {
+ perror("calloc");
+ (void) close(fd);
+ continue;
+ }
+ if (ioctl(fd, SESIOC_GETOBJMAP, (caddr_t) objp) < 0) {
+ perror("SESIOC_GETOBJMAP");
+ (void) close(fd);
+ continue;
+ }
+ for (i = 0; i < nobj; i++) {
+ printf(" Object %d: ID 0x%x Type '%s'\n", i,
+ objp[i].obj_id, geteltnm((int)objp[i].object_type));
+ }
+ free(objp);
+ (void) close(fd);
+ }
+ return (0);
+}
diff --git a/share/examples/ses/srcs/getobjstat.c b/share/examples/ses/srcs/getobjstat.c
new file mode 100644
index 000000000000..83a5e6462961
--- /dev/null
+++ b/share/examples/ses/srcs/getobjstat.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_ses.h>
+
+int
+main(int a, char **v)
+{
+ int fd;
+ int i;
+ ses_objstat obj;
+ long cvt;
+ char *x;
+
+ if (a != 3) {
+usage:
+ fprintf(stderr, "usage: %s device objectid\n", *v);
+ return (1);
+ }
+ fd = open(v[1], O_RDONLY);
+ if (fd < 0) {
+ perror(v[1]);
+ return (1);
+ }
+ x = v[2];
+ cvt = strtol(v[2], &x, 0);
+ if (x == v[2]) {
+ goto usage;
+ }
+ obj.obj_id = cvt;
+ if (ioctl(fd, SESIOC_GETOBJSTAT, (caddr_t) &obj) < 0) {
+ perror("SESIOC_GETOBJSTAT");
+ return (1);
+ }
+ fprintf(stdout, "Object 0x%x: 0x%x 0x%x 0x%x 0x%x\n", obj.obj_id,
+ obj.cstat[0], obj.cstat[1], obj.cstat[2], obj.cstat[3]);
+ (void) close(fd);
+ return (0);
+}
diff --git a/share/examples/ses/srcs/inienc.c b/share/examples/ses/srcs/inienc.c
new file mode 100644
index 000000000000..f72e71552f7b
--- /dev/null
+++ b/share/examples/ses/srcs/inienc.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_ses.h>
+
+int
+main(int a, char **v)
+{
+ int fd;
+
+ while (*++v) {
+ fd = open(*v, O_RDWR);
+ if (fd < 0) {
+ perror(*v);
+ continue;
+ }
+ if (ioctl(fd, SESIOC_INIT, NULL) < 0) {
+ perror("SESIOC_GETNOBJ");
+ }
+ (void) close(fd);
+ }
+ return (0);
+}
diff --git a/share/examples/ses/srcs/sesd.c b/share/examples/ses/srcs/sesd.c
new file mode 100644
index 000000000000..9a6cb8cfe34a
--- /dev/null
+++ b/share/examples/ses/srcs/sesd.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_enc.h>
+
+#define ALLSTAT (SES_ENCSTAT_UNRECOV | SES_ENCSTAT_CRITICAL | \
+ SES_ENCSTAT_NONCRITICAL | SES_ENCSTAT_INFO)
+
+/*
+ * Monitor named SES devices and note (via syslog) any changes in status.
+ */
+
+int
+main(int a, char **v)
+{
+ static const char *usage =
+ "usage: %s [ -c ] [ -d ] [ -t pollinterval ] device [ device ]\n";
+ int fd, polltime, dev, nodaemon, clear, c;
+ encioc_enc_status_t stat, nstat, *carray;
+
+ if (a < 2) {
+ fprintf(stderr, usage, *v);
+ return (1);
+ }
+
+ nodaemon = 0;
+ polltime = 30;
+ clear = 0;
+ while ((c = getopt(a, v, "cdt:")) != -1) {
+ switch (c) {
+ case 'c':
+ clear = 1;
+ break;
+ case 'd':
+ nodaemon = 1;
+ break;
+ case 't':
+ polltime = atoi(optarg);
+ break;
+ default:
+ fprintf(stderr, usage, *v);
+ return (1);
+ }
+ }
+
+ carray = malloc(a);
+ if (carray == NULL) {
+ perror("malloc");
+ return (1);
+ }
+ for (dev = optind; dev < a; dev++)
+ carray[dev] = (encioc_enc_status_t) -1;
+
+ /*
+ * Check to make sure we can open all devices
+ */
+ for (dev = optind; dev < a; dev++) {
+ fd = open(v[dev], O_RDWR);
+ if (fd < 0) {
+ perror(v[dev]);
+ return (1);
+ }
+ if (ioctl(fd, ENCIOC_INIT, NULL) < 0) {
+ fprintf(stderr, "%s: ENCIOC_INIT fails- %s\n",
+ v[dev], strerror(errno));
+ return (1);
+ }
+ (void) close(fd);
+ }
+ if (nodaemon == 0) {
+ if (daemon(0, 0) < 0) {
+ perror("daemon");
+ return (1);
+ }
+ openlog("sesd", LOG_CONS, LOG_USER);
+ } else {
+ openlog("sesd", LOG_CONS|LOG_PERROR, LOG_USER);
+ }
+
+ for (;;) {
+ for (dev = optind; dev < a; dev++) {
+ fd = open(v[dev], O_RDWR);
+ if (fd < 0) {
+ syslog(LOG_ERR, "%s: %m", v[dev]);
+ continue;
+ }
+
+ /*
+ * Get the actual current enclosure status.
+ */
+ if (ioctl(fd, ENCIOC_GETENCSTAT, (caddr_t) &stat) < 0) {
+ syslog(LOG_ERR,
+ "%s: ENCIOC_GETENCSTAT- %m", v[dev]);
+ (void) close(fd);
+ continue;
+ }
+ if (stat != 0 && clear) {
+ nstat = 0;
+ if (ioctl(fd, ENCIOC_SETENCSTAT,
+ (caddr_t) &nstat) < 0) {
+ syslog(LOG_ERR,
+ "%s: ENCIOC_SETENCSTAT- %m", v[dev]);
+ }
+ }
+ (void) close(fd);
+
+ if (stat == carray[dev])
+ continue;
+
+ carray[dev] = stat;
+ if ((stat & ALLSTAT) == 0) {
+ syslog(LOG_NOTICE,
+ "%s: Enclosure Status OK", v[dev]);
+ }
+ if (stat & SES_ENCSTAT_INFO) {
+ syslog(LOG_NOTICE,
+ "%s: Enclosure Has Information", v[dev]);
+ }
+ if (stat & SES_ENCSTAT_NONCRITICAL) {
+ syslog(LOG_WARNING,
+ "%s: Enclosure Non-Critical", v[dev]);
+ }
+ if (stat & SES_ENCSTAT_CRITICAL) {
+ syslog(LOG_CRIT,
+ "%s: Enclosure Critical", v[dev]);
+ }
+ if (stat & SES_ENCSTAT_UNRECOV) {
+ syslog(LOG_ALERT,
+ "%s: Enclosure Unrecoverable", v[dev]);
+ }
+ }
+ sleep(polltime);
+ }
+ /* NOTREACHED */
+}
diff --git a/share/examples/ses/srcs/setencstat.c b/share/examples/ses/srcs/setencstat.c
new file mode 100644
index 000000000000..dbfbaf27aacb
--- /dev/null
+++ b/share/examples/ses/srcs/setencstat.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_enc.h>
+
+int
+main(int a, char **v)
+{
+ int fd;
+ long val;
+ encioc_enc_status_t stat;
+
+ if (a != 3) {
+ fprintf(stderr, "usage: %s device enclosure_status\n", *v);
+ return (1);
+ }
+ fd = open(v[1], O_RDWR);
+ if (fd < 0) {
+ perror(v[1]);
+ return (1);
+ }
+
+ val = strtol(v[2], NULL, 0);
+ stat = (encioc_enc_status_t)val;
+ if (ioctl(fd, ENCIOC_SETENCSTAT, (caddr_t) &stat) < 0) {
+ perror("ENCIOC_SETENCSTAT");
+ }
+ (void) close(fd);
+ return (0);
+}
diff --git a/share/examples/ses/srcs/setobjstat.c b/share/examples/ses/srcs/setobjstat.c
new file mode 100644
index 000000000000..e5d374e5252a
--- /dev/null
+++ b/share/examples/ses/srcs/setobjstat.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2000 by Matthew Jacob
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * the GNU Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Matthew Jacob
+ * Feral Software
+ * mjacob@feral.com
+ */
+
+#include <unistd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_enc.h>
+
+int
+main(int a, char **v)
+{
+ int fd;
+ int i;
+ encioc_elm_status_t obj;
+ long cvt;
+ char *x;
+
+ if (a != 7) {
+usage:
+ fprintf(stderr,
+ "usage: %s device objectid stat0 stat1 stat2 stat3\n", *v);
+ return (1);
+ }
+ fd = open(v[1], O_RDWR);
+ if (fd < 0) {
+ perror(v[1]);
+ return (1);
+ }
+ x = v[2];
+ cvt = strtol(v[2], &x, 0);
+ if (x == v[2]) {
+ goto usage;
+ }
+ obj.elm_idx = cvt;
+ for (i = 0; i < 4; i++) {
+ x = v[3 + i];
+ cvt = strtol(v[3 + i], &x, 0);
+ if (x == v[3 + i]) {
+ goto usage;
+ }
+ obj.cstat[i] = cvt;
+ }
+ if (ioctl(fd, ENCIOC_SETELMSTAT, (caddr_t) &obj) < 0) {
+ perror("ENCIOC_SETELMSTAT");
+ }
+ (void) close(fd);
+ return (0);
+}
diff --git a/share/examples/smbfs/Makefile b/share/examples/smbfs/Makefile
new file mode 100644
index 000000000000..e38305148005
--- /dev/null
+++ b/share/examples/smbfs/Makefile
@@ -0,0 +1,10 @@
+
+PACKAGE=utilities
+FILESDIR= ${SHAREDIR}/examples/smbfs
+FILES= dot.nsmbrc
+
+.PATH: ${SRCTOP}/contrib/smbfs/examples
+
+SUBDIR= print
+
+.include <bsd.prog.mk>
diff --git a/share/examples/smbfs/Makefile.depend b/share/examples/smbfs/Makefile.depend
new file mode 100644
index 000000000000..11aba52f82cf
--- /dev/null
+++ b/share/examples/smbfs/Makefile.depend
@@ -0,0 +1,10 @@
+# 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/share/examples/smbfs/print/Makefile b/share/examples/smbfs/print/Makefile
new file mode 100644
index 000000000000..0a0fd500724f
--- /dev/null
+++ b/share/examples/smbfs/print/Makefile
@@ -0,0 +1,8 @@
+
+PACKAGE=utilities
+FILESDIR= ${SHAREDIR}/examples/smbfs/print
+FILES= lj6l ljspool printcap.sample tolj
+
+.PATH: ${SRCTOP}/contrib/smbfs/examples/print
+
+.include <bsd.prog.mk>
diff --git a/share/examples/smbfs/print/Makefile.depend b/share/examples/smbfs/print/Makefile.depend
new file mode 100644
index 000000000000..11aba52f82cf
--- /dev/null
+++ b/share/examples/smbfs/print/Makefile.depend
@@ -0,0 +1,10 @@
+# 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/share/examples/sound/README b/share/examples/sound/README
new file mode 100644
index 000000000000..0188a26348c8
--- /dev/null
+++ b/share/examples/sound/README
@@ -0,0 +1,66 @@
+Briefly summarised, a general audio application will:
+- open(2)
+- ioctl(2)
+- read(2)
+- write(2)
+- close(2)
+
+In this example, read/write will be called in a loop for a duration of
+record/playback. Usually, /dev/dsp is the device you want to open, but it can
+be any OSS compatible device, even user space one created with virtual_oss. For
+configuring sample rate, bit depth and all other configuring of the device
+ioctl is used. As devices can support multiple sample rates and formats, what
+specific application should do in case there's an error issuing ioctl, as not
+all errors are fatal, is upon the developer to decide. As a general guideline
+Official OSS development howto should be used. FreeBSD OSS and virtual_oss are
+different to a small degree.
+
+For more advanced OSS and real-time applications, developers need to handle
+buffers more carefully. The size of the buffer in OSS is selected using fragment
+size size_selector and the buffer size is 2^size_selector for values between 4
+and 16. The formula on the official site is:
+
+int frag = (max_fragments << 16) | (size_selector);
+ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &frag);
+
+The max_fragments determines in how many fragments the buffer will be, hence if
+the size_selector is 4, the requested size is 2^4 = 16 and for the
+max_fragments of 2, the total buffer size will be
+
+(2 ^ size_selector) * max_fragments
+
+or in this case 32 bytes. Please note that size of buffer is in bytes not
+samples. For example, 24bit sample will be represented with 3 bytes. If you're
+porting audio app from Linux, you should be aware that 24 bit samples are
+represented with 4 bytes (usually int).
+
+FreeBSD kernel will round up max_fragments and size of fragment/buffer, so the
+last thing any OSS code should do is get info about buffer with audio_buf_info
+and SNDCTL_DSP_GETOSPACE. That also means that not all values of max_fragments
+are permitted.
+
+From kernel perspective, there are few points OSS developers should be aware of:
+- There is a software facing buffer (bs) and a hardware driver buffer (b)
+- The sizes can be seen with cat /dev/sndstat as [b:_/_/_] [bs:_/_/_] (needed:
+ sysctl hw.snd.verbose=2)
+- OSS ioctl only concern software buffer fragments, not hardware
+
+For USB the block size is according to hw.usb.uaudio.buffer_ms sysctl, meaning
+2ms at 48kHz gives 0.002 * 48000 = 96 samples per block, all multiples of this
+work well. Block size for virtual_oss, if used, should be set accordingly.
+
+OSS driver insists on reading / writing a certain number of samples at a time,
+one fragment full of samples. It is bound to do so in a fixed time frame, to
+avoid under- and overruns in communication with the hardware.
+
+The idea of a total buffer size that holds max_fragments fragments is to give
+some slack and allow application to be about max_fragments - 1 fragments late.
+Let's call this the jitter tolerance. The jitter tolerance may be much less if
+there is a slight mismatch between the period and the samples per fragment.
+
+Jitter tolerance gets better if we can make either the period or the samples
+per fragment considerably smaller than the other. In our case that means we
+divide the total buffer size into smaller fragments, keeping overall latency at
+the same level.
+
+Official OSS development howto: http://manuals.opensound.com/developer/DSP.html
diff --git a/share/examples/sound/basic.c b/share/examples/sound/basic.c
new file mode 100644
index 000000000000..83ecbe6ea9a7
--- /dev/null
+++ b/share/examples/sound/basic.c
@@ -0,0 +1,99 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Goran Mekić
+ *
+ * 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 "ossinit.h"
+
+int
+main()
+{
+ config_t config = {
+ .device = "/dev/dsp",
+ .channels = -1,
+ .format = format,
+ .frag = -1,
+ .sample_rate = 48000,
+ .sample_size = sizeof(sample_t),
+ .buffer_info.fragments = -1,
+ .mmap = 0,
+ };
+
+ /* Initialize device */
+ oss_init(&config);
+
+ /*
+ * Allocate input and output buffers so that their size match
+ * frag_size
+ */
+ int ret;
+ int bytes = config.buffer_info.bytes;
+ int8_t *ibuf = malloc(bytes);
+ int8_t *obuf = malloc(bytes);
+ sample_t *channels = malloc(bytes);
+
+ printf(
+ "bytes: %d, fragments: %d, fragsize: %d, fragstotal: %d, samples: %d\n",
+ bytes,
+ config.buffer_info.fragments,
+ config.buffer_info.fragsize,
+ config.buffer_info.fragstotal,
+ config.sample_count
+ );
+
+ /* Minimal engine: read input and copy it to the output */
+ for (;;) {
+ ret = read(config.fd, ibuf, bytes);
+ if (ret < bytes) {
+ fprintf(
+ stderr,
+ "Requested %d bytes, but read %d!\n",
+ bytes,
+ ret
+ );
+ break;
+ }
+ oss_split(&config, (sample_t *)ibuf, channels);
+ /* All processing will happen here */
+ oss_merge(&config, channels, (sample_t *)obuf);
+ ret = write(config.fd, obuf, bytes);
+ if (ret < bytes) {
+ fprintf(
+ stderr,
+ "Requested %d bytes, but wrote %d!\n",
+ bytes,
+ ret
+ );
+ break;
+ }
+ }
+
+ /* Cleanup */
+ free(channels);
+ free(obuf);
+ free(ibuf);
+ close(config.fd);
+ return (0);
+}
diff --git a/share/examples/sound/midi.c b/share/examples/sound/midi.c
new file mode 100644
index 000000000000..6d6ac9aa0fcd
--- /dev/null
+++ b/share/examples/sound/midi.c
@@ -0,0 +1,76 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Goran Mekić
+ *
+ * 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 <unistd.h>
+
+#include "ossmidi.h"
+
+int
+main()
+{
+ midi_event_t event;
+ midi_config_t midi_config;
+ int l = -1;
+ unsigned char raw;
+
+ midi_config.device = "/dev/umidi1.0";
+ oss_midi_init(&midi_config);
+
+ while ((l = read(midi_config.fd, &raw, sizeof(raw))) != -1) {
+ if (!(raw & 0x80)) {
+ continue;
+ }
+ event.type = raw & CMD_MASK;
+ event.channel = raw & CHANNEL_MASK;
+ switch (event.type) {
+ case NOTE_ON:
+ case NOTE_OFF:
+ case CONTROLLER_ON:
+ if ((l = read(midi_config.fd, &(event.note), sizeof(event.note))) == -1) {
+ perror("Error reading MIDI note");
+ exit(1);
+ }
+ if ((l = read(midi_config.fd, &(event.velocity), sizeof(event.velocity))) == -1) {
+ perror("Error reading MIDI velocity");
+ exit(1);
+ }
+ break;
+ }
+ switch (event.type) {
+ case NOTE_ON:
+ case NOTE_OFF:
+ printf("Channel %d, note %d, velocity %d\n", event.channel, event.note, event.velocity);
+ break;
+ case CONTROLLER_ON:
+ printf("Channel %d, controller %d, value %d\n", event.channel, event.controller, event.value);
+ break;
+ default:
+ printf("Unknown event type %d\n", event.type);
+ }
+ }
+ return 0;
+}
diff --git a/share/examples/sound/ossinit.h b/share/examples/sound/ossinit.h
new file mode 100644
index 000000000000..83920712286d
--- /dev/null
+++ b/share/examples/sound/ossinit.h
@@ -0,0 +1,262 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2021 Goran Mekić
+ *
+ * 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/soundcard.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+#ifndef SAMPLE_SIZE
+#define SAMPLE_SIZE 16
+#endif
+
+/* Format can be unsigned, in which case replace S with U */
+#if SAMPLE_SIZE == 32
+typedef int32_t sample_t;
+int format = AFMT_S32_NE; /* Signed 32bit native endian format */
+#elif SAMPLE_SIZE == 16
+typedef int16_t sample_t;
+int format = AFMT_S16_NE; /* Signed 16bit native endian format */
+#elif SAMPLE_SIZE == 8
+typedef int8_t sample_t;
+int format = AFMT_S8_NE; /* Signed 8bit native endian format */
+#else
+#error Unsupported sample format!
+typedef int32_t sample_t;
+int format = AFMT_S32_NE; /* Not a real value, just silencing
+ * compiler errors */
+#endif
+
+
+
+/*
+ * Minimal configuration for OSS
+ * For real world applications, this structure will probably contain many
+ * more fields
+ */
+typedef struct config {
+ char *device;
+ int channels;
+ int fd;
+ int format;
+ int frag;
+ int sample_count;
+ int sample_rate;
+ int sample_size;
+ int chsamples;
+ int mmap;
+ oss_audioinfo audio_info;
+ audio_buf_info buffer_info;
+} config_t;
+
+
+/*
+ * Error state is indicated by value=-1 in which case application exits
+ * with error
+ */
+static inline void
+check_error(const int value, const char *message)
+{
+ if (value == -1) {
+ fprintf(stderr, "OSS error: %s %s\n", message, strerror(errno));
+ exit(1);
+ }
+}
+
+
+
+/* Calculate frag by giving it minimal size of buffer */
+static inline int
+size2frag(int x)
+{
+ int frag = 0;
+
+ while ((1 << frag) < x) {
+ ++frag;
+ }
+ return frag;
+}
+
+
+/*
+ * Split input buffer into channels. Input buffer is in interleaved format
+ * which means if we have 2 channels (L and R), this is what the buffer of
+ * 8 samples would contain: L,R,L,R,L,R,L,R. The result are two channels
+ * containing: L,L,L,L and R,R,R,R.
+ */
+void
+oss_split(config_t *config, sample_t *input, sample_t *output)
+{
+ int channel;
+ int index;
+
+ for (int i = 0; i < config->sample_count; ++i) {
+ channel = i % config->channels;
+ index = i / config->channels;
+ output[channel * index] = input[i];
+ }
+}
+
+
+/*
+ * Convert channels into interleaved format and place it in output
+ * buffer
+ */
+void
+oss_merge(config_t *config, sample_t *input, sample_t *output)
+{
+ for (int channel = 0; channel < config->channels; ++channel) {
+ for (int index = 0; index < config->chsamples; ++index) {
+ output[index * config->channels + channel] = input[channel * index];
+ }
+ }
+}
+
+void
+oss_init(config_t *config)
+{
+ int error;
+ int tmp;
+
+ /* Open the device for read and write */
+ config->fd = open(config->device, O_RDWR);
+ check_error(config->fd, "open");
+
+ /* Get device information */
+ config->audio_info.dev = -1;
+ error = ioctl(config->fd, SNDCTL_ENGINEINFO, &(config->audio_info));
+ check_error(error, "SNDCTL_ENGINEINFO");
+ printf("min_channels: %d\n", config->audio_info.min_channels);
+ printf("max_channels: %d\n", config->audio_info.max_channels);
+ printf("latency: %d\n", config->audio_info.latency);
+ printf("handle: %s\n", config->audio_info.handle);
+ if (config->audio_info.min_rate > config->sample_rate || config->sample_rate > config->audio_info.max_rate) {
+ fprintf(stderr, "%s doesn't support chosen ", config->device);
+ fprintf(stderr, "samplerate of %dHz!\n", config->sample_rate);
+ exit(1);
+ }
+ if (config->channels < 1) {
+ config->channels = config->audio_info.max_channels;
+ }
+
+ /*
+ * If device is going to be used in mmap mode, disable all format
+ * conversions. Official OSS documentation states error code should not be
+ * checked. http://manuals.opensound.com/developer/mmap_test.c.html#LOC10
+ */
+ if (config->mmap) {
+ tmp = 0;
+ ioctl(config->fd, SNDCTL_DSP_COOKEDMODE, &tmp);
+ }
+
+ /*
+ * Set number of channels. If number of channels is chosen to the value
+ * near the one wanted, save it in config
+ */
+ tmp = config->channels;
+ error = ioctl(config->fd, SNDCTL_DSP_CHANNELS, &tmp);
+ check_error(error, "SNDCTL_DSP_CHANNELS");
+ if (tmp != config->channels) { /* or check if tmp is close enough? */
+ fprintf(stderr, "%s doesn't support chosen ", config->device);
+ fprintf(stderr, "channel count of %d", config->channels);
+ fprintf(stderr, ", set to %d!\n", tmp);
+ }
+ config->channels = tmp;
+
+ /* Set format, or bit size: 8, 16, 24 or 32 bit sample */
+ tmp = config->format;
+ error = ioctl(config->fd, SNDCTL_DSP_SETFMT, &tmp);
+ check_error(error, "SNDCTL_DSP_SETFMT");
+ if (tmp != config->format) {
+ fprintf(stderr, "%s doesn't support chosen sample format!\n", config->device);
+ exit(1);
+ }
+
+ /* Most common values for samplerate (in kHz): 44.1, 48, 88.2, 96 */
+ tmp = config->sample_rate;
+ error = ioctl(config->fd, SNDCTL_DSP_SPEED, &tmp);
+ check_error(error, "SNDCTL_DSP_SPEED");
+
+ /* Get and check device capabilities */
+ error = ioctl(config->fd, SNDCTL_DSP_GETCAPS, &(config->audio_info.caps));
+ check_error(error, "SNDCTL_DSP_GETCAPS");
+ if (!(config->audio_info.caps & PCM_CAP_DUPLEX)) {
+ fprintf(stderr, "Device doesn't support full duplex!\n");
+ exit(1);
+ }
+ if (config->mmap) {
+ if (!(config->audio_info.caps & PCM_CAP_TRIGGER)) {
+ fprintf(stderr, "Device doesn't support triggering!\n");
+ exit(1);
+ }
+ if (!(config->audio_info.caps & PCM_CAP_MMAP)) {
+ fprintf(stderr, "Device doesn't support mmap mode!\n");
+ exit(1);
+ }
+ }
+
+ /*
+ * If desired frag is smaller than minimum, based on number of channels
+ * and format (size in bits: 8, 16, 24, 32), set that as frag. Buffer size
+ * is 2^frag, but the real size of the buffer will be read when the
+ * configuration of the device is successful
+ */
+ int min_frag = size2frag(config->sample_size * config->channels);
+
+ if (config->frag < min_frag) {
+ config->frag = min_frag;
+ }
+
+ /*
+ * Allocate buffer in fragments. Total buffer will be split in number
+ * of fragments (2 by default)
+ */
+ if (config->buffer_info.fragments < 0) {
+ config->buffer_info.fragments = 2;
+ }
+ tmp = ((config->buffer_info.fragments) << 16) | config->frag;
+ error = ioctl(config->fd, SNDCTL_DSP_SETFRAGMENT, &tmp);
+ check_error(error, "SNDCTL_DSP_SETFRAGMENT");
+
+ /* When all is set and ready to go, get the size of buffer */
+ error = ioctl(config->fd, SNDCTL_DSP_GETOSPACE, &(config->buffer_info));
+ check_error(error, "SNDCTL_DSP_GETOSPACE");
+ if (config->buffer_info.bytes < 1) {
+ fprintf(
+ stderr,
+ "OSS buffer error: buffer size can not be %d\n",
+ config->buffer_info.bytes
+ );
+ exit(1);
+ }
+ config->sample_count = config->buffer_info.bytes / config->sample_size;
+ config->chsamples = config->sample_count / config->channels;
+}
diff --git a/share/examples/sound/ossmidi.h b/share/examples/sound/ossmidi.h
new file mode 100644
index 000000000000..99a6bacffe73
--- /dev/null
+++ b/share/examples/sound/ossmidi.h
@@ -0,0 +1,63 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2022 Goran Mekić
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+#define CMD_MASK 0xF0
+#define NOTE_ON 0x90
+#define NOTE_OFF 0x80
+#define CHANNEL_MASK 0xF
+#define CONTROLLER_ON 0xB0
+
+typedef struct midi_event {
+ unsigned char type;
+ unsigned char channel;
+ union {
+ unsigned char note;
+ unsigned controller;
+ };
+ union {
+ unsigned char velocity;
+ unsigned char value;
+ };
+} midi_event_t;
+
+typedef struct midi_config {
+ char *device;
+ int fd;
+} midi_config_t;
+
+void
+oss_midi_init(midi_config_t *config)
+{
+ if ((config->fd = open(config->device, O_RDWR)) == -1) {
+ perror("Error opening MIDI device");
+ exit(1);
+ }
+}
diff --git a/share/examples/sunrpc/Makefile b/share/examples/sunrpc/Makefile
new file mode 100644
index 000000000000..231d2f0262f5
--- /dev/null
+++ b/share/examples/sunrpc/Makefile
@@ -0,0 +1,25 @@
+# Build all demo services
+#
+#
+
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/sunrpc
+MAKE = make
+LIB=
+
+SUBDIR= dir msg sort
+
+all: ${SUBDIR}
+
+clean cleanup:
+ cd dir; $(MAKE) ${MFLAGS} cleanup
+ cd msg; $(MAKE) ${MFLAGS} cleanup
+ cd sort; $(MAKE) ${MFLAGS} cleanup
+
+install:
+ @echo "No installations done."
+
+${SUBDIR}: FRC
+ cd $@; $(MAKE) ${MFLAGS} LIB=$(LIB)
+
+FRC:
diff --git a/share/examples/sunrpc/dir/Makefile b/share/examples/sunrpc/dir/Makefile
new file mode 100644
index 000000000000..5d66e639025d
--- /dev/null
+++ b/share/examples/sunrpc/dir/Makefile
@@ -0,0 +1,25 @@
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/sunrpc/dir
+BIN = dir_svc rls
+GEN = dir_clnt.c dir_svc.c dir_xdr.c dir.h
+LIB = -lrpclib
+RPCCOM = rpcgen
+
+all: $(BIN)
+
+$(GEN): dir.x
+ $(RPCCOM) dir.x
+
+dir_svc: dir_proc.o dir_svc.o dir_xdr.o
+ $(CC) -o $@ dir_proc.o dir_svc.o dir_xdr.o $(LIB)
+
+rls: rls.o dir_clnt.o dir_xdr.o
+ $(CC) -o $@ rls.o dir_clnt.o dir_xdr.o $(LIB)
+
+rls.o: rls.c dir.h
+
+dir_proc.o: dir_proc.c dir.h
+
+clean cleanup:
+ rm -f $(GEN) *.o $(BIN)
+
diff --git a/share/examples/sunrpc/dir/dir.x b/share/examples/sunrpc/dir/dir.x
new file mode 100644
index 000000000000..ddd5d0f43c4e
--- /dev/null
+++ b/share/examples/sunrpc/dir/dir.x
@@ -0,0 +1,36 @@
+/*
+ * dir.x: Remote directory listing protocol
+ */
+const MAXNAMELEN = 255; /* maximum length of a directory entry */
+
+typedef string nametype<MAXNAMELEN>; /* a directory entry */
+
+typedef struct namenode *namelist; /* a link in the listing */
+
+/*
+ * A node in the directory listing
+ */
+struct namenode {
+ nametype name; /* name of directory entry */
+ namelist next; /* next entry */
+};
+
+/*
+ * The result of a READDIR operation.
+ */
+union readdir_res switch (int errno) {
+case 0:
+ namelist list; /* no error: return directory listing */
+default:
+ void; /* error occurred: nothing else to return */
+};
+
+/*
+ * The directory program definition
+ */
+program DIRPROG {
+ version DIRVERS {
+ readdir_res
+ READDIR(nametype) = 1;
+ } = 1;
+} = 76;
diff --git a/share/examples/sunrpc/dir/dir_proc.c b/share/examples/sunrpc/dir/dir_proc.c
new file mode 100644
index 000000000000..afeda53d5243
--- /dev/null
+++ b/share/examples/sunrpc/dir/dir_proc.c
@@ -0,0 +1,54 @@
+/*
+ * dir_proc.c: remote readdir implementation
+ */
+#include <rpc/rpc.h>
+#include <sys/dir.h>
+#include "dir.h"
+
+extern int errno;
+extern char *malloc();
+extern char *strcpy();
+
+readdir_res *
+readdir_1(dirname)
+ nametype *dirname;
+{
+ DIR *dirp;
+ struct direct *d;
+ namelist nl;
+ namelist *nlp;
+ static readdir_res res; /* must be static! */
+
+ /*
+ * Open directory
+ */
+ dirp = opendir(*dirname);
+ if (dirp == NULL) {
+ res.errno = errno;
+ return (&res);
+ }
+
+ /*
+ * Free previous result
+ */
+ xdr_free(xdr_readdir_res, &res);
+
+ /*
+ * Collect directory entries
+ */
+ nlp = &res.readdir_res_u.list;
+ while (d = readdir(dirp)) {
+ nl = *nlp = (namenode *) malloc(sizeof(namenode));
+ nl->name = malloc(strlen(d->d_name)+1);
+ strcpy(nl->name, d->d_name);
+ nlp = &nl->next;
+ }
+ *nlp = NULL;
+
+ /*
+ * Return the result
+ */
+ res.errno = 0;
+ closedir(dirp);
+ return (&res);
+}
diff --git a/share/examples/sunrpc/dir/rls.c b/share/examples/sunrpc/dir/rls.c
new file mode 100644
index 000000000000..5c39b7139e14
--- /dev/null
+++ b/share/examples/sunrpc/dir/rls.c
@@ -0,0 +1,80 @@
+/*
+ * rls.c: Remote directory listing client
+ */
+#include <stdio.h>
+#include <rpc/rpc.h> /* always need this */
+#include "dir.h" /* need this too: will be generated by rpcgen*/
+
+extern int errno;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ CLIENT *cl;
+ char *server;
+ char *dir;
+ readdir_res *result;
+ namelist nl;
+
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s host directory\n", argv[0]);
+ exit(1);
+ }
+
+ /*
+ * Remember what our command line arguments refer to
+ */
+ server = argv[1];
+ dir = argv[2];
+
+ /*
+ * Create client "handle" used for calling DIRPROG on the
+ * server designated on the command line. We tell the rpc package
+ * to use the "tcp" protocol when contacting the server.
+ */
+ cl = clnt_create(server, DIRPROG, DIRVERS, "tcp");
+ if (cl == NULL) {
+ /*
+ * Couldn't establish connection with server.
+ * Print error message and die.
+ */
+ clnt_pcreateerror(server);
+ exit(1);
+ }
+
+ /*
+ * Call the remote procedure "readdir" on the server
+ */
+ result = readdir_1(&dir, cl);
+ if (result == NULL) {
+ /*
+ * An error occurred while calling the server.
+ * Print error message and die.
+ */
+ clnt_perror(cl, server);
+ exit(1);
+ }
+
+ /*
+ * Okay, we successfully called the remote procedure.
+ */
+ if (result->errno != 0) {
+ /*
+ * A remote system error occurred.
+ * Print error message and die.
+ */
+ errno = result->errno;
+ perror(dir);
+ exit(1);
+ }
+
+ /*
+ * Successfully got a directory listing.
+ * Print it out.
+ */
+ for (nl = result->readdir_res_u.list; nl != NULL; nl = nl->next) {
+ printf("%s\n", nl->name);
+ }
+}
diff --git a/share/examples/sunrpc/msg/Makefile b/share/examples/sunrpc/msg/Makefile
new file mode 100644
index 000000000000..4ccb7f62e3db
--- /dev/null
+++ b/share/examples/sunrpc/msg/Makefile
@@ -0,0 +1,35 @@
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/sunrpc/msg
+BIN = printmsg msg_svc rprintmsg
+GEN = msg_clnt.c msg_svc.c msg.h
+LIB = -lrpclib
+RPCCOM = rpcgen
+
+all: $(BIN)
+
+#
+# This is the non-networked version of the program
+#
+printmsg: printmsg.o
+ $(CC) -o $@ printmsg.o
+
+#
+# note: no xdr routines are generated here, due this service's
+# use of basic data types.
+#
+$(GEN): msg.x
+ $(RPCCOM) msg.x
+
+msg_svc: msg_proc.o msg_svc.o
+ $(CC) -o $@ msg_proc.o msg_svc.o $(LIB)
+
+rprintmsg: rprintmsg.o msg_clnt.o
+ $(CC) -o $@ rprintmsg.o msg_clnt.o $(LIB)
+
+rprintmsg.o: rprintmsg.c msg.h
+
+msg_proc.o: msg_proc.c msg.h
+
+clean cleanup:
+ rm -f $(GEN) *.o $(BIN)
+
diff --git a/share/examples/sunrpc/msg/msg.x b/share/examples/sunrpc/msg/msg.x
new file mode 100644
index 000000000000..8df021add840
--- /dev/null
+++ b/share/examples/sunrpc/msg/msg.x
@@ -0,0 +1,8 @@
+/*
+ * msg.x: Remote message printing protocol
+ */
+program MESSAGEPROG {
+ version MESSAGEVERS {
+ int PRINTMESSAGE(string) = 1;
+ } = 1;
+} = 99;
diff --git a/share/examples/sunrpc/msg/msg_proc.c b/share/examples/sunrpc/msg/msg_proc.c
new file mode 100644
index 000000000000..bd0797fc15bc
--- /dev/null
+++ b/share/examples/sunrpc/msg/msg_proc.c
@@ -0,0 +1,28 @@
+/*
+ * msg_proc.c: implementation of the remote procedure "printmessage"
+ */
+#include <paths.h>
+#include <stdio.h>
+#include <rpc/rpc.h> /* always need this here */
+#include "msg.h" /* need this too: msg.h will be generated by rpcgen */
+
+/*
+ * Remote version of "printmessage"
+ */
+int *
+printmessage_1(msg)
+ char **msg;
+{
+ static int result; /* must be static! */
+ FILE *f;
+
+ f = fopen(_PATH_CONSOLE, "w");
+ if (f == NULL) {
+ result = 0;
+ return (&result);
+ }
+ fprintf(f, "%s\n", *msg);
+ fclose(f);
+ result = 1;
+ return (&result);
+}
diff --git a/share/examples/sunrpc/msg/printmsg.c b/share/examples/sunrpc/msg/printmsg.c
new file mode 100644
index 000000000000..6058eb94fb82
--- /dev/null
+++ b/share/examples/sunrpc/msg/printmsg.c
@@ -0,0 +1,43 @@
+/*
+ * printmsg.c: print a message on the console
+ */
+#include <paths.h>
+#include <stdio.h>
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char *message;
+
+ if (argc < 2) {
+ fprintf(stderr, "usage: %s <message>\n", argv[0]);
+ exit(1);
+ }
+ message = argv[1];
+
+ if (!printmessage(message)) {
+ fprintf(stderr, "%s: sorry, couldn't print your message\n",
+ argv[0]);
+ exit(1);
+ }
+ printf("Message delivered!\n");
+}
+
+/*
+ * Print a message to the console.
+ * Return a boolean indicating whether the message was actually printed.
+ */
+printmessage(msg)
+ char *msg;
+{
+ FILE *f;
+
+ f = fopen(_PATH_CONSOLE, "w");
+ if (f == NULL) {
+ return (0);
+ }
+ fprintf(f, "%s\n", msg);
+ fclose(f);
+ return(1);
+}
diff --git a/share/examples/sunrpc/msg/rprintmsg.c b/share/examples/sunrpc/msg/rprintmsg.c
new file mode 100644
index 000000000000..25f09cb097dc
--- /dev/null
+++ b/share/examples/sunrpc/msg/rprintmsg.c
@@ -0,0 +1,73 @@
+/*
+ * rprintmsg.c: remote version of "printmsg.c"
+ */
+#include <stdio.h>
+#include <rpc/rpc.h> /* always need this */
+#include "msg.h" /* need this too: will be generated by rpcgen*/
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ CLIENT *cl;
+ int *result;
+ char *server;
+ char *message;
+
+ if (argc < 3) {
+ fprintf(stderr, "usage: %s host message\n", argv[0]);
+ exit(1);
+ }
+
+ /*
+ * Remember what our command line arguments refer to
+ */
+ server = argv[1];
+ message = argv[2];
+
+ /*
+ * Create client "handle" used for calling MESSAGEPROG on the
+ * server designated on the command line. We tell the rpc package
+ * to use the "tcp" protocol when contacting the server.
+ */
+ cl = clnt_create(server, MESSAGEPROG, MESSAGEVERS, "tcp");
+ if (cl == NULL) {
+ /*
+ * Couldn't establish connection with server.
+ * Print error message and die.
+ */
+ clnt_pcreateerror(server);
+ exit(1);
+ }
+
+ /*
+ * Call the remote procedure "printmessage" on the server
+ */
+ result = printmessage_1(&message, cl);
+ if (result == NULL) {
+ /*
+ * An error occurred while calling the server.
+ * Print error message and die.
+ */
+ clnt_perror(cl, server);
+ exit(1);
+ }
+
+ /*
+ * Okay, we successfully called the remote procedure.
+ */
+ if (*result == 0) {
+ /*
+ * Server was unable to print our message.
+ * Print error message and die.
+ */
+ fprintf(stderr, "%s: sorry, %s couldn't print your message\n",
+ argv[0], server);
+ exit(1);
+ }
+
+ /*
+ * The message got printed on the server's console
+ */
+ printf("Message delivered to %s!\n", server);
+}
diff --git a/share/examples/sunrpc/sort/Makefile b/share/examples/sunrpc/sort/Makefile
new file mode 100644
index 000000000000..9ea4044b0b67
--- /dev/null
+++ b/share/examples/sunrpc/sort/Makefile
@@ -0,0 +1,34 @@
+PACKAGE=examples
+FILESDIR=${SHAREDIR}/examples/sunrpc/sort
+BIN = rsort sort_svc
+GEN = sort_clnt.c sort_svc.c sort_xdr.c sort.h
+LIB = -lrpclib
+RPCCOM = rpcgen
+
+all: $(BIN)
+
+rsort: rsort.o sort_clnt.o sort_xdr.o
+ $(CC) $(LDFLAGS) -o $@ rsort.o sort_clnt.o sort_xdr.o $(LIB)
+
+rsort.o: rsort.c sort.h
+
+sort_clnt.c:
+ $(RPCCOM) -l sort.x >$@
+
+sort_svc: sort_proc.o sort_svc.o sort_xdr.o
+ $(CC) $(LDFLAGS) -o $@ sort_proc.o sort_svc.o sort_xdr.o $(LIB)
+
+sort_proc.o: sort_proc.c sort.h
+
+sort_svc.c:
+ $(RPCCOM) -s udp sort.x >$@
+
+sort_xdr.c:
+ $(RPCCOM) -c sort.x >$@
+
+sort.h:
+ $(RPCCOM) -h sort.x >$@
+
+clean cleanup:
+ rm -f $(GEN) *.o $(BIN)
+
diff --git a/share/examples/sunrpc/sort/rsort.c b/share/examples/sunrpc/sort/rsort.c
new file mode 100644
index 000000000000..1a96d826d096
--- /dev/null
+++ b/share/examples/sunrpc/sort/rsort.c
@@ -0,0 +1,42 @@
+/*
+ * rsort.c
+ * Client side application which sorts argc, argv.
+ */
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include "sort.h"
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *machinename;
+ struct sortstrings args, res;
+ int i;
+
+ if (argc < 3) {
+ fprintf(stderr, "usage: %s machinename [s1 ...]\n", argv[0]);
+ exit(1);
+ }
+ machinename = argv[1];
+ args.ss.ss_len = argc - 2; /* substract off progname, machinename */
+ args.ss.ss_val = &argv[2];
+ res.ss.ss_val = (char **)NULL;
+
+ if ((i = callrpc(machinename, SORTPROG, SORTVERS, SORT,
+ xdr_sortstrings, &args, xdr_sortstrings, &res)))
+ {
+ fprintf(stderr, "%s: call to sort service failed. ", argv[0]);
+ clnt_perrno(i);
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+
+ for (i = 0; i < res.ss.ss_len; i++) {
+ printf("%s\n", res.ss.ss_val[i]);
+ }
+
+ /* should free res here */
+ exit(0);
+}
+
diff --git a/share/examples/sunrpc/sort/sort.x b/share/examples/sunrpc/sort/sort.x
new file mode 100644
index 000000000000..9db635fa0eb5
--- /dev/null
+++ b/share/examples/sunrpc/sort/sort.x
@@ -0,0 +1,18 @@
+/*
+ * The sort procedure receives an array of strings and returns an array
+ * of strings. This toy service handles a maximum of 64 strings.
+ */
+const MAXSORTSIZE = 64;
+const MAXSTRINGLEN = 64;
+
+typedef string str<MAXSTRINGLEN>; /* the string itself */
+
+struct sortstrings {
+ str ss<MAXSORTSIZE>;
+};
+
+program SORTPROG {
+ version SORTVERS {
+ sortstrings SORT(sortstrings) = 1;
+ } = 1;
+} = 22855;
diff --git a/share/examples/sunrpc/sort/sort_proc.c b/share/examples/sunrpc/sort/sort_proc.c
new file mode 100644
index 000000000000..d09df48ca883
--- /dev/null
+++ b/share/examples/sunrpc/sort/sort_proc.c
@@ -0,0 +1,26 @@
+#include <rpc/rpc.h>
+#include "sort.h"
+
+static int
+comparestrings(sp1, sp2)
+ char **sp1, **sp2;
+{
+ return (strcmp(*sp1, *sp2));
+}
+
+struct sortstrings *
+sort_1(ssp)
+ struct sortstrings *ssp;
+{
+ static struct sortstrings ss_res;
+
+ if (ss_res.ss.ss_val != (str *)NULL)
+ free(ss_res.ss.ss_val);
+
+ qsort(ssp->ss.ss_val, ssp->ss.ss_len, sizeof (char *), comparestrings);
+ ss_res.ss.ss_len = ssp->ss.ss_len;
+ ss_res.ss.ss_val = (str *)malloc(ssp->ss.ss_len * sizeof(str *));
+ bcopy(ssp->ss.ss_val, ss_res.ss.ss_val,
+ ssp->ss.ss_len * sizeof(str *));
+ return(&ss_res);
+}
diff --git a/share/examples/tests/Makefile b/share/examples/tests/Makefile
new file mode 100644
index 000000000000..8f257929d60f
--- /dev/null
+++ b/share/examples/tests/Makefile
@@ -0,0 +1,7 @@
+
+SUBDIR= tests
+
+.PATH: ${SRCTOP}/tests
+KYUAFILE= yes
+
+.include <bsd.test.mk>
diff --git a/share/examples/tests/Makefile.depend b/share/examples/tests/Makefile.depend
new file mode 100644
index 000000000000..11aba52f82cf
--- /dev/null
+++ b/share/examples/tests/Makefile.depend
@@ -0,0 +1,10 @@
+# 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/share/examples/tests/README b/share/examples/tests/README
new file mode 100644
index 000000000000..ecf3c36a01f1
--- /dev/null
+++ b/share/examples/tests/README
@@ -0,0 +1,36 @@
+
+This directory contains sample test programs along the Makefile and
+Kyuafile logic to get them build and installed.
+
+The goal of these test programs is to illustrate, via simple and
+heaviliy-commented code, how to construct test programs using all the
+supported interfaces in the system.
+
+If you use any files in here as templates for your own code, please
+remove all comments while doing so and then write your own if necessary.
+
+The subdirectories here contain:
+
+* tests/: Regular directory containing the tests code. Note that the
+ apparently-redundant tests/tests/ path component here is expected for
+ consistency reasons and required to get the right layout under
+ /usr/tests/.
+
+* tests/atf/: Tests that use the ATF libraries, including atf-c, atf-c++
+ and atf-sh. See kyua-atf-interface(1) for details.
+
+* tests/plain/: Tests that do not use any testing framework. See
+ kyua-plain-interface(1) for details.
+
+To inspect the available sample test cases from an installed system:
+
+ $ kyua list -k /usr/tests/share/examples/tests/Kyuafile
+
+To run the full suite of sample test cases:
+
+ $ kyua test -k /usr/tests/share/examples/tests/Kyuafile
+
+And to debug a specific failing test case, if any:
+
+ $ kyua debug -k /usr/tests/share/examples/tests/Kyuafile \
+ atf/cp_test:simple
diff --git a/share/examples/tests/tests/Makefile b/share/examples/tests/tests/Makefile
new file mode 100644
index 000000000000..ecaa1b5b9037
--- /dev/null
+++ b/share/examples/tests/tests/Makefile
@@ -0,0 +1,35 @@
+
+.include <src.opts.mk>
+
+# Directory into which the Kyuafile provided by this directory will be
+# installed.
+#
+# This is always a subdirectory of ${TESTSBASE}/. The remainder of the
+# path has to match the relative path within the source tree in which
+# these files are found modulo the tests/ component at the end.
+#
+# For example: if this Makefile were in src/bin/cp/tests/, its TESTSDIR
+# would point at ${TESTSBASE}/bin/cp/.
+#
+# The default path specified by bsd.test.mk is `${TESTSBASE}/${RELDIR:H}`,
+# which happens to be the same as `${TESTSBASE}/share/examples/tests`.
+#TESTSDIR= ${TESTSBASE}/share/examples/tests
+
+# List of subdirectories into which we want to recurse during the build
+# of the system. We use TESTS_SUBDIRS instead of SUBDIR because we want
+# the auto-generated Kyuafile to recurse into these directories.
+TESTS_SUBDIRS+= atf
+TESTS_SUBDIRS+= plain
+TESTS_SUBDIRS+= tap
+
+.if ${MK_GOOGLETEST} != no
+TESTS_SUBDIRS+= googletest
+.endif
+
+# We leave KYUAFILE unset so that bsd.test.mk auto-generates a Kyuafile
+# for us based on the contents of the TESTS_SUBDIRS line above. The
+# generated file will tell the tests run-time engine to recurse into the
+# directories listed above.
+#KYUAFILE= auto
+
+.include <bsd.test.mk>
diff --git a/share/examples/tests/tests/Makefile.depend b/share/examples/tests/tests/Makefile.depend
new file mode 100644
index 000000000000..11aba52f82cf
--- /dev/null
+++ b/share/examples/tests/tests/Makefile.depend
@@ -0,0 +1,10 @@
+# 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/share/examples/tests/tests/atf/Kyuafile b/share/examples/tests/tests/atf/Kyuafile
new file mode 100644
index 000000000000..ef2407d0f11c
--- /dev/null
+++ b/share/examples/tests/tests/atf/Kyuafile
@@ -0,0 +1,45 @@
+--
+-- Copyright 2013 Google Inc.
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions are
+-- met:
+--
+-- * 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.
+-- * Neither the name of Google Inc. nor the names of its contributors
+-- may be used to endorse or promote products derived from this software
+-- without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE 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.
+
+syntax(2)
+
+-- All tests provided by the FreeBSD base system should set the test_suite
+-- property to FreeBSD. This creates a namespace in the configuration file
+-- in which specific run-time properties can be passed to the tests below.
+test_suite('FreeBSD')
+
+-- Register the various test programs into the test suite defined in this
+-- directory.
+--
+-- Note that, while Kyua supports overriding the test case metadata
+-- properties (e.g. their timeout) along the test program definition, you
+-- should not do so for ATF test programs. The ATF test cases themselves
+-- encode the right values.
+atf_test_program{name='cp_test'}
+atf_test_program{name='printf_test'}
diff --git a/share/examples/tests/tests/atf/Makefile b/share/examples/tests/tests/atf/Makefile
new file mode 100644
index 000000000000..7614767b6e0a
--- /dev/null
+++ b/share/examples/tests/tests/atf/Makefile
@@ -0,0 +1,52 @@
+
+# The release package to use for the tests contained within the directory
+#
+# This applies to components which rely on ^/projects/release-pkg support
+# (see UPDATING XXXXXXXXX / svn revision r298107).
+PACKAGE= tests
+
+# Directory into which the Kyuafile provided by this directory will be
+# installed.
+#
+# This is always a subdirectory of ${TESTSBASE}/. The remainder of the
+# path has to match the relative path within the source tree in which
+# these files are found modulo the tests/ component at the end.
+#
+# For example: if this Makefile were in src/bin/cp/tests/, its TESTSDIR
+# would point at ${TESTSBASE}/bin/cp/.
+TESTSDIR= ${TESTSBASE}/share/examples/tests/atf
+
+# List of test programs to build. Note that we can build more than one
+# test from a single directory, and this is expected.
+ATF_TESTS_C= printf_test
+ATF_TESTS_SH= cp_test
+
+# Tell bsd.test.mk that we are providing a hand-crafted Kyuafile in this
+# directory. We do so because the file in this directory exists for
+# documentation purposes.
+#
+# In general, however, you should NOT define KYUAFILE at all to allow
+# bsd.test.mk auto-generate one for you based on the ATF_TESTS_*
+# definitions from above.
+KYUAFILE= yes
+
+# Install file1 and file2 as files via bsd.progs.mk. Please note the intentional
+# ${PACKAGE} namespace of files.
+#
+# The basic semantics of this are the same as FILES in bsd.progs.mk, e.g. the
+# installation of the files can be manipulated via ${PACKAGE}FILESDIR,
+# ${PACKAGE}FILESMODE, etc.
+#
+# Please see comment above about ${PACKAGE}. Feel free to omit the ${PACKAGE}
+# namespace if release package support isn't needed.
+${PACKAGE}FILES+= file1
+CLEANFILES+= file1
+
+file1:
+ @echo "File 1" > ${.TARGET}
+
+.include <bsd.test.mk>
+
+.if ${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} >= 180000
+CWARNFLAGS.printf_test.c+= -Wno-format-truncation
+.endif
diff --git a/share/examples/tests/tests/atf/Makefile.depend b/share/examples/tests/tests/atf/Makefile.depend
new file mode 100644
index 000000000000..1af0c88e099c
--- /dev/null
+++ b/share/examples/tests/tests/atf/Makefile.depend
@@ -0,0 +1,17 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/atf/libatf-c \
+ 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/share/examples/tests/tests/atf/cp_test.sh b/share/examples/tests/tests/atf/cp_test.sh
new file mode 100644
index 000000000000..d06786c9d0ce
--- /dev/null
+++ b/share/examples/tests/tests/atf/cp_test.sh
@@ -0,0 +1,120 @@
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Copyright 2013 Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * 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.
+# * Neither the name of Google Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE 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.
+
+#
+# INTRODUCTION
+#
+# This sample test program implements various test cases for the cp(1)
+# utility in order to demonstrate the usage of the ATF shell API (see
+# atf-sh-api(3)).
+#
+
+#
+# Auxiliary function to compare two files for equality.
+#
+verify_copy() {
+ if ! cmp -s "${1}" "${2}"; then
+ echo "${1} and ${2} differ, but they should be equal"
+ diff -u "${1}" "${2}"
+ atf_fail "Original and copy do not match"
+ fi
+}
+
+#
+# This is the simplest form of a test case definition: a test case
+# without a header.
+#
+# In most cases, this is the definition you will want to use. However,
+# make absolutely sure that the test case name is descriptive enough.
+# Multi-word test case names are encouraged. Keep in mind that these
+# are exposed to the reader in the test reports, and the goal is for
+# the combination of the test program plus the name of the test case to
+# give a pretty clear idea of what specific condition the test is
+# validating.
+#
+atf_test_case simple
+simple_body() {
+ cp $(atf_get_srcdir)/file1 .
+
+ # The atf_check function is a very powerful function of atf-sh.
+ # It allows you to define checkers for the exit status, the
+ # stdout and the stderr of any command you execute. If the
+ # result of the command does not match the expectations defined
+ # in the checkers, the test fails and verbosely reports data
+ # behind the problem.
+ #
+ # See atf-check(1) for details.
+ atf_check -s exit:0 -o empty -e empty cp file1 file2
+
+ verify_copy file1 file2
+
+ # Of special note here is that we are NOT deleting the temporary
+ # files we created in this test. Kyua takes care of this
+ # cleanup automatically and tests can (and should) rely on this
+ # behavior.
+}
+
+#
+# This is a more complex form of a test case definition: a test case
+# with a header and a body. You should always favor the simpler
+# definition above unless you have to override specific metadata
+# variables.
+#
+# See atf-test-case(4) and kyua-atf-interface(1) for details on all
+# available properties.
+#
+atf_test_case force
+force_head() {
+ # In this specific case, we define a textual description for
+ # the test case, which is later exported to the reports for
+ # documentation purposes.
+ #
+ # However, note again that you should favor highly descriptive
+ # test case names to textual descriptions.
+ atf_set "descr" "Tests that the -f flag causes cp to forcibly" \
+ "override the destination file"
+}
+force_body() {
+ cp $(atf_get_srcdir)/file1 .
+ echo 'File 2' >file2
+ chmod 400 file2
+ atf_check cp -f file1 file2
+ verify_copy file1 file2
+}
+
+#
+# Lastly, we tell ATF which test cases exist in this program. This
+# function should not do anything other than this registration.
+#
+atf_init_test_cases() {
+ atf_add_test_case simple
+ atf_add_test_case force
+}
diff --git a/share/examples/tests/tests/atf/printf_test.c b/share/examples/tests/tests/atf/printf_test.c
new file mode 100644
index 000000000000..d837c6b7686f
--- /dev/null
+++ b/share/examples/tests/tests/atf/printf_test.c
@@ -0,0 +1,158 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2013 Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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. */
+
+/*
+ * INTRODUCTION
+ *
+ * This sample test program implements various test cases for the printf(3)
+ * family of functions in order to demonstrate the usage of the ATF C API
+ * (see atf-c-api(3)).
+ *
+ * Note that this test program is called printf_test because it is intended
+ * to validate various functions of the printf(3) family. For this reason,
+ * each test is prefixed with the name of the function under test followed
+ * by a description of the specific condition being validated. You should
+ * use a similar naming scheme for your own tests.
+ */
+
+#include <atf-c.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * This is the simplest form of a test case definition: a test case
+ * without a header.
+ *
+ * In most cases, this is the definition you will want to use. However,
+ * make absolutely sure that the test case name is descriptive enough.
+ * Multi-word test case names are encouraged. Keep in mind that these
+ * are exposed to the reader in the test reports, and the goal is for
+ * the combination of the test program plus the name of the test case to
+ * give a pretty clear idea of what specific condition the test is
+ * validating.
+ */
+ATF_TC_WITHOUT_HEAD(snprintf__two_formatters);
+ATF_TC_BODY(snprintf__two_formatters, tc)
+{
+ char buffer[128];
+
+ /* This first require-style check invokes the function we are
+ * interested in testing. This will cause the test to fail if
+ * the condition provided to ATF_REQUIRE is not met. */
+ ATF_REQUIRE(snprintf(buffer, sizeof(buffer), "%s, %s!",
+ "Hello", "tests") > 0);
+
+ /* This second check-style check compares that the result of the
+ * snprintf call we performed above is correct. We use a check
+ * instead of a require. */
+ ATF_CHECK_STREQ("Hello, tests!", buffer);
+}
+
+/*
+ * This is a more complex form of a test case definition: a test case
+ * with a header and a body. You should always favor the simpler
+ * definition above unless you have to override specific metadata
+ * variables.
+ *
+ * See atf-test-case(4) and kyua-atf-interface(1) for details on all
+ * available properties.
+ */
+ATF_TC(snprintf__overflow);
+ATF_TC_HEAD(snprintf__overflow, tc)
+{
+ /* In this specific case, we define a textual description for
+ * the test case, which is later exported to the reports for
+ * documentation purposes.
+ *
+ * However, note again that you should favor highly descriptive
+ * test case names to textual descriptions. */
+ atf_tc_set_md_var(tc, "descr", "This test case validates the proper "
+ "truncation of the output string from snprintf when it does not "
+ "fit the provided buffer.");
+}
+ATF_TC_BODY(snprintf__overflow, tc)
+{
+ char buffer[10];
+
+ /* This is a similar test to the above, but in this case we do the
+ * test ourselves and forego the ATF_* macros. Note that we use the
+ * atf_tc_fail() function instead of exit(2) or similar because we
+ * want Kyua to have access to the failure message.
+ *
+ * In general, prefer using the ATF_* macros wherever possible. Only
+ * resort to manual tests when the macros are unsuitable (and consider
+ * filing a feature request to get a new macro if you think your case
+ * is generic enough). */
+ if (snprintf(buffer, sizeof(buffer), "0123456789abcdef") != 16)
+ atf_tc_fail("snprintf did not return the expected number "
+ "of characters");
+
+ ATF_CHECK(strcmp(buffer, "012345678") == 0);
+}
+
+/*
+ * Another simple test case, but this time with side-effects. This
+ * particular test case modifies the contents of the current directory
+ * and does not clean up after itself, which is perfectly fine.
+ */
+ATF_TC_WITHOUT_HEAD(fprintf__simple_string);
+ATF_TC_BODY(fprintf__simple_string, tc)
+{
+ const char *contents = "This is a message\n";
+
+ FILE *output = fopen("test.txt", "w");
+ ATF_REQUIRE(fprintf(output, "%s", contents) > 0);
+ fclose(output);
+
+ /* The ATF C library provides more than just macros to verify the
+ * outcome of expressions. It also includes various helper functions
+ * to work with files and processes. Here is just a simple
+ * example. */
+ ATF_REQUIRE(atf_utils_compare_file("test.txt", contents));
+
+ /* Of special note here is that we are NOT deleting the
+ * temporary files we created in this test. Kyua takes care of
+ * this cleanup automatically and tests can (and should) rely on
+ * this behavior. */
+}
+
+/*
+ * Lastly, we tell ATF which test cases exist in this program. This
+ * function should not do anything other than this registration.
+ */
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, snprintf__two_formatters);
+ ATF_TP_ADD_TC(tp, snprintf__overflow);
+ ATF_TP_ADD_TC(tp, fprintf__simple_string);
+
+ return (atf_no_error());
+}
diff --git a/share/examples/tests/tests/googletest/Makefile b/share/examples/tests/tests/googletest/Makefile
new file mode 100644
index 000000000000..57bfc3a12dff
--- /dev/null
+++ b/share/examples/tests/tests/googletest/Makefile
@@ -0,0 +1,58 @@
+#
+# This Makefile differs from the other examples, in the sense that its purpose
+# is to install the upstream provided googletest sample unit tests.
+
+# The release package to use for the tests contained within the directory
+#
+# This applies to components which rely on ^/projects/release-pkg support
+# (see UPDATING XXXXXXXXX / svn revision r298107).
+PACKAGE= tests
+
+# Directory into which the Kyuafile provided by this directory will be
+# installed.
+#
+# This is always a subdirectory of ${TESTSBASE}/. The remainder of the
+# path has to match the relative path within the source tree in which
+# these files are found modulo the tests/ component at the end.
+#
+# For example: if this Makefile were in src/bin/cp/tests/, its TESTSDIR
+# would point at ${TESTSBASE}/bin/cp/.
+TESTSDIR= ${TESTSBASE}/share/examples/tests/googletest
+
+.PATH: ${SRCTOP}/contrib/googletest/googletest/samples
+
+GTEST_MAIN_REQ_TESTS+= sample1_unittest
+GTEST_MAIN_REQ_TESTS+= sample2_unittest
+GTEST_MAIN_REQ_TESTS+= sample3_unittest
+GTEST_MAIN_REQ_TESTS+= sample4_unittest
+GTEST_MAIN_REQ_TESTS+= sample5_unittest
+GTEST_MAIN_REQ_TESTS+= sample6_unittest
+GTEST_MAIN_REQ_TESTS+= sample7_unittest
+GTEST_MAIN_REQ_TESTS+= sample8_unittest
+
+# sample9_unittest's `CustomOutputTest.Fails` fails intentionally to illustrate
+# how output format can be adjusted with command-line parameters.
+#GTEST_REQ_TESTS+= sample9_unittest
+GTEST_REQ_TESTS+= sample10_unittest
+
+# List of test programs to build. Note that we can build more than one
+# test from a single directory, and this is expected.
+GTESTS+= ${GTEST_MAIN_REQ_TESTS} ${GTEST_REQ_TESTS}
+
+#
+.for t in ${GTESTS}
+.if ${GTEST_MAIN_REQ_TESTS:M$t}
+LIBADD.$t+= gtest_main
+.else
+LIBADD.$t+= gtest
+.endif
+SRCS.$t+= $t.cc
+.endfor
+
+# Additional sources for sample testcase 1, 2, 4, and 5.
+SRCS.sample1_unittest+= sample1.cc
+SRCS.sample2_unittest+= sample2.cc
+SRCS.sample4_unittest+= sample4.cc
+SRCS.sample5_unittest+= sample1.cc
+
+.include <bsd.test.mk>
diff --git a/share/examples/tests/tests/plain/Kyuafile b/share/examples/tests/tests/plain/Kyuafile
new file mode 100644
index 000000000000..c427a6045e95
--- /dev/null
+++ b/share/examples/tests/tests/plain/Kyuafile
@@ -0,0 +1,46 @@
+--
+-- Copyright 2013 Google Inc.
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions are
+-- met:
+--
+-- * 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.
+-- * Neither the name of Google Inc. nor the names of its contributors
+-- may be used to endorse or promote products derived from this software
+-- without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE 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.
+
+syntax(2)
+
+-- All tests provided by the FreeBSD base system should set the test_suite
+-- property to FreeBSD. This creates a namespace in the configuration file
+-- in which specific run-time properties can be passed to the tests below.
+test_suite('FreeBSD')
+
+-- Register the various test programs into the test suite defined in this
+-- directory.
+--
+-- Because plain test programs cannot define metadata in their code (they
+-- have no mechanism to communicate that to Kyua), we can instead define
+-- any metadata properties in here. These have the exact same meaning as
+-- their ATF counterparts. These properties are often useful to define
+-- prerequisites for the execution of the tests.
+plain_test_program{name='cp_test', required_programs='/bin/cp'}
+plain_test_program{name='printf_test'}
diff --git a/share/examples/tests/tests/plain/Makefile b/share/examples/tests/tests/plain/Makefile
new file mode 100644
index 000000000000..462324309f6a
--- /dev/null
+++ b/share/examples/tests/tests/plain/Makefile
@@ -0,0 +1,52 @@
+
+# The release package to use for the tests contained within the directory
+#
+# This applies to components which rely on ^/projects/release-pkg support
+# (see UPDATING XXXXXXXXX / svn revision r298107).
+PACKAGE= tests
+
+# Directory into which the Kyuafile provided by this directory will be
+# installed.
+#
+# This is always a subdirectory of ${TESTSBASE}/. The remainder of the
+# path has to match the relative path within the source tree in which
+# these files are found modulo the tests/ component at the end.
+#
+# For example: if this Makefile were in src/bin/cp/tests/, its TESTSDIR
+# would point at ${TESTSBASE}/bin/cp/.
+TESTSDIR= ${TESTSBASE}/share/examples/tests/plain
+
+# List of test programs to build. Note that we can build more than one
+# test from a single directory, and this is expected.
+PLAIN_TESTS_C= printf_test
+PLAIN_TESTS_SH= cp_test
+
+# Tell bsd.test.mk that we are providing a hand-crafted Kyuafile in this
+# directory. We do so because the file in this directory exists for
+# documentation purposes.
+#
+# In general, however, you should NOT define KYUAFILE at all to allow
+# bsd.test.mk auto-generate one for you based on the PLAIN_TESTS_*
+# definitions from above.
+KYUAFILE= yes
+
+# Install file1 and file2 as files via bsd.progs.mk. Please note the intentional
+# ${PACKAGE} namespace of files.
+#
+# The basic semantics of this are the same as FILES in bsd.progs.mk, e.g. the
+# installation of the files can be manipulated via ${PACKAGE}FILESDIR,
+# ${PACKAGE}FILESMODE, etc.
+#
+# Please see comment above about ${PACKAGE}. Feel free to omit the ${PACKAGE}
+# namespace if release package support isn't needed.
+${PACKAGE}FILES+= file1
+CLEANFILES+= file1
+
+file1:
+ @echo "File 1" > ${.TARGET}
+
+.include <bsd.test.mk>
+
+.if ${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} >= 180000
+CWARNFLAGS.printf_test.c+= -Wno-format-truncation
+.endif
diff --git a/share/examples/tests/tests/plain/Makefile.depend b/share/examples/tests/tests/plain/Makefile.depend
new file mode 100644
index 000000000000..84b8ddd67e34
--- /dev/null
+++ b/share/examples/tests/tests/plain/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ 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/share/examples/tests/tests/plain/cp_test.sh b/share/examples/tests/tests/plain/cp_test.sh
new file mode 100644
index 000000000000..d7c813d504b2
--- /dev/null
+++ b/share/examples/tests/tests/plain/cp_test.sh
@@ -0,0 +1,83 @@
+#! /bin/sh
+#
+# Copyright 2013 Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * 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.
+# * Neither the name of Google Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE 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.
+
+#
+# INTRODUCTION
+#
+# This plain test program mimics the structure and contents of its
+# ATF-based counterpart. It attempts to represent various test cases
+# in different separate functions and just calls them all from main.
+#
+# In reality, plain test programs can be much simpler. All they have
+# to do is return 0 on success and non-0 otherwise.
+#
+
+set -e
+
+# Prints an error message and exits.
+err() {
+ echo "${@}" 1>&2
+ exit 1
+}
+
+# Auxiliary function to compare two files for equality.
+verify_copy() {
+ if ! cmp -s "${1}" "${2}"; then
+ diff -u "${1}" "${2}"
+ err "${1} and ${2} differ, but they should be equal"
+ fi
+}
+
+simple_test() {
+ cp "$(dirname "${0}")/file1" .
+ cp file1 file2 || err "cp failed"
+ verify_copy file1 file2
+}
+
+force_test() {
+ echo 'File 3' >file3
+ chmod 400 file3
+ cp -f file1 file3 || err "cp failed"
+ verify_copy file1 file3
+}
+
+# If you have read the cp_test.sh counterpart in the atf/ directory, you
+# may think that the sequencing of tests below and the exposed behavior
+# to the user is very similar. But you'd be wrong.
+#
+# There are two major differences with this and the ATF version. The
+# first is that the code below has no provisions to detect failures in
+# one test and continue running the other tests: the first failure
+# causes the whole test program to exit. The second is that this
+# particular "main" has no arguments: without ATF, all test programs may
+# expose a different command-line interface, and this is an issue for
+# consistency purposes.
+simple_test
+force_test
diff --git a/share/examples/tests/tests/plain/printf_test.c b/share/examples/tests/tests/plain/printf_test.c
new file mode 100644
index 000000000000..09c46086a58b
--- /dev/null
+++ b/share/examples/tests/tests/plain/printf_test.c
@@ -0,0 +1,121 @@
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2013 Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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. */
+
+/*
+ * INTRODUCTION
+ *
+ * This plain test program mimics the structure and contents of its
+ * ATF-based counterpart. It attempts to represent various test cases
+ * in different separate functions and just calls them all from main().
+ *
+ * In reality, plain test programs can be much simpler. All they have
+ * to do is return 0 on success and non-0 otherwise.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void
+snprintf__two_formatters(void)
+{
+ char buffer[128];
+
+ if (snprintf(buffer, sizeof(buffer), "%s, %s!", "Hello",
+ "tests") <= 0)
+ errx(EXIT_FAILURE, "snprintf with two formatters failed");
+
+ if (strcmp(buffer, "Hello, tests!") != 0)
+ errx(EXIT_FAILURE, "Bad formatting: got %s", buffer);
+}
+
+static void
+snprintf__overflow(void)
+{
+ char buffer[10];
+
+ if (snprintf(buffer, sizeof(buffer), "0123456789abcdef") != 16)
+ errx(EXIT_FAILURE, "snprintf did not return the expected "
+ "number of characters");
+
+ if (strcmp(buffer, "012345678") != 0)
+ errx(EXIT_FAILURE, "Bad formatting: got %s", buffer);
+}
+
+static void
+fprintf__simple_string(void)
+{
+ FILE *file;
+ char buffer[128];
+ size_t length;
+ const char *contents = "This is a message\n";
+
+ file = fopen("test.txt", "w+");
+ if (fprintf(file, "%s", contents) <= 0)
+ err(EXIT_FAILURE, "fprintf failed to write to file");
+ rewind(file);
+ length = fread(buffer, 1, sizeof(buffer) - 1, file);
+ if (length != strlen(contents))
+ err(EXIT_FAILURE, "fread failed");
+ buffer[length] = '\0';
+ fclose(file);
+
+ if (strcmp(buffer, contents) != 0)
+ errx(EXIT_FAILURE, "Written and read data differ");
+
+ /* Of special note here is that we are NOT deleting the temporary
+ * files we created in this test. Kyua takes care of this cleanup
+ * automatically and tests can (and should) rely on this behavior. */
+}
+
+int
+main(void)
+{
+ /* If you have read the printf_test.c counterpart in the atf/
+ * directory, you may think that the sequencing of tests below and
+ * the exposed behavior to the user is very similar. But you'd be
+ * wrong.
+ *
+ * There are two major differences with this and the ATF version.
+ * The first is that the code below has no provisions to detect
+ * failures in one test and continue running the other tests: the
+ * first failure causes the whole test program to exit. The second
+ * is that this particular main() has no arguments: without ATF,
+ * all test programs may expose a different command-line interface,
+ * and this is an issue for consistency purposes. */
+ snprintf__two_formatters();
+ snprintf__overflow();
+ fprintf__simple_string();
+
+ return EXIT_SUCCESS;
+}
diff --git a/share/examples/tests/tests/tap/Kyuafile b/share/examples/tests/tests/tap/Kyuafile
new file mode 100644
index 000000000000..64339c54c012
--- /dev/null
+++ b/share/examples/tests/tests/tap/Kyuafile
@@ -0,0 +1,46 @@
+--
+-- Copyright 2013 Google Inc.
+-- All rights reserved.
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions are
+-- met:
+--
+-- * 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.
+-- * Neither the name of Google Inc. nor the names of its contributors
+-- may be used to endorse or promote products derived from this software
+-- without specific prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE 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.
+
+syntax(2)
+
+-- All tests provided by the FreeBSD base system should set the test_suite
+-- property to FreeBSD. This creates a namespace in the configuration file
+-- in which specific run-time properties can be passed to the tests below.
+test_suite('FreeBSD')
+
+-- Register the various test programs into the test suite defined in this
+-- directory.
+--
+-- Because plain test programs cannot define metadata in their code (they
+-- have no mechanism to communicate that to Kyua), we can instead define
+-- any metadata properties in here. These have the exact same meaning as
+-- their ATF counterparts. These properties are often useful to define
+-- prerequisites for the execution of the tests.
+tap_test_program{name='cp_test', required_programs='/bin/cp'}
+tap_test_program{name='printf_test'}
diff --git a/share/examples/tests/tests/tap/Makefile b/share/examples/tests/tests/tap/Makefile
new file mode 100644
index 000000000000..86d3f6805045
--- /dev/null
+++ b/share/examples/tests/tests/tap/Makefile
@@ -0,0 +1,52 @@
+
+# The release package to use for the tests contained within the directory
+#
+# This applies to components which rely on ^/projects/release-pkg support
+# (see UPDATING XXXXXXXXX / svn revision r298107).
+PACKAGE= tests
+
+# Directory into which the Kyuafile provided by this directory will be
+# installed.
+#
+# This is always a subdirectory of ${TESTSBASE}/. The remainder of the
+# path has to match the relative path within the source tree in which
+# these files are found modulo the tests/ component at the end.
+#
+# For example: if this Makefile were in src/bin/cp/tests/, its TESTSDIR
+# would point at ${TESTSBASE}/bin/cp/.
+TESTSDIR= ${TESTSBASE}/share/examples/tests/tap
+
+# List of test programs to build. Note that we can build more than one
+# test from a single directory, and this is expected.
+TAP_TESTS_C= printf_test
+TAP_TESTS_SH= cp_test
+
+# Tell bsd.test.mk that we are providing a hand-crafted Kyuafile in this
+# directory. We do so because the file in this directory exists for
+# documentation purposes.
+#
+# In general, however, you should NOT define KYUAFILE at all to allow
+# bsd.test.mk auto-generate one for you based on the PLAIN_TESTS_*
+# definitions from above.
+KYUAFILE= yes
+
+# Install file1 and file2 as files via bsd.prog.mk. Please note the intentional
+# ${PACKAGE} namespace of files.
+#
+# The basic semantics of this are the same as FILES in bsd.prog.mk, e.g. the
+# installation of the files can be manipulated via ${PACKAGE}FILESDIR,
+# ${PACKAGE}FILESMODE, etc.
+#
+# Please see comment above about ${PACKAGE}. Feel free to omit the ${PACKAGE}
+# namespace if release package support isn't needed.
+${PACKAGE}FILES+= file1
+CLEANFILES+= file1
+
+file1:
+ @echo "File 1" > ${.TARGET}
+
+.include <bsd.test.mk>
+
+.if ${COMPILER_TYPE} == "clang" && ${COMPILER_VERSION} >= 180000
+CWARNFLAGS.printf_test.c+= -Wno-format-truncation
+.endif
diff --git a/share/examples/tests/tests/tap/Makefile.depend b/share/examples/tests/tests/tap/Makefile.depend
new file mode 100644
index 000000000000..84b8ddd67e34
--- /dev/null
+++ b/share/examples/tests/tests/tap/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ 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/share/examples/tests/tests/tap/cp_test.sh b/share/examples/tests/tests/tap/cp_test.sh
new file mode 100644
index 000000000000..118c2001ae71
--- /dev/null
+++ b/share/examples/tests/tests/tap/cp_test.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+#
+# Copyright (c) 2017 Enji Cooper <ngie@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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+#
+
+#
+# INTRODUCTION
+#
+# This TAP test program mimics the structure and contents of its
+# ATF-based counterpart. It attempts to represent various test cases
+# in different separate functions and just calls them all from main.
+#
+
+test_num=1
+TEST_COUNT=4
+
+result()
+{
+ local result=$1; shift
+ local result_string
+
+ result_string="$result $test_num"
+ if [ $# -gt 0 ]; then
+ result_string="$result_string - $@"
+ fi
+ echo "$result_string"
+ : $(( test_num += 1 ))
+}
+
+# Auxiliary function to compare two files for equality.
+verify_copy() {
+ if cmp -s "${1}" "${2}"; then
+ result "ok"
+ else
+ result "not ok" "${1} and ${2} differ, but they should be equal"
+ diff -u "${1}" "${2}"
+ fi
+}
+
+simple_test() {
+ cp "$(dirname "${0}")/file1" .
+ if cp file1 file2; then
+ result "ok"
+ verify_copy file1 file2
+ else
+ result "not ok" "cp failed"
+ result "not ok" "# SKIP"
+ fi
+}
+
+force_test() {
+ echo 'File 3' >file3
+ chmod 400 file3
+ if cp -f file1 file3; then
+ result "ok"
+ verify_copy file1 file3
+ else
+ result "not ok" "cp -f failed"
+ result "not ok" "# SKIP"
+ fi
+}
+
+# If you have read the cp_test.sh counterpart in the atf/ directory, you
+# may think that the sequencing of tests below and the exposed behavior
+# to the user is very similar. But you'd be wrong.
+#
+# There are two major differences with this and the ATF version. First off,
+# the TAP test doesn't isolate simple_test from force_test, whereas the ATF
+# version does. Secondly, the test script accepts arbitrary command line
+# inputs.
+echo "1..$TEST_COUNT"
+
+simple_test
+force_test
+exit 0
diff --git a/share/examples/tests/tests/tap/printf_test.c b/share/examples/tests/tests/tap/printf_test.c
new file mode 100644
index 000000000000..62ab64722f8b
--- /dev/null
+++ b/share/examples/tests/tests/tap/printf_test.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2013 Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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. */
+
+/*
+ * INTRODUCTION
+ *
+ * This plain test program mimics the structure and contents of its
+ * ATF-based counterpart. It attempts to represent various test cases
+ * in different separate functions and just calls them all from main().
+ *
+ * In reality, plain test programs can be much simpler. All they have
+ * to do is return 0 on success and non-0 otherwise.
+ */
+
+#include <err.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int failed;
+static int test_num = 1;
+
+#define TEST_COUNT 7
+
+static void
+fail(const char *fmt, ...)
+{
+ char *msg;
+ va_list ap;
+
+ failed = 1;
+
+ va_start(ap, fmt);
+ if (vasprintf(&msg, fmt, ap) == -1)
+ err(1, NULL);
+ va_end(ap);
+ printf("not ok %d - %s\n", test_num, msg);
+ free(msg);
+
+ test_num++;
+}
+
+static void
+pass(void)
+{
+
+ printf("ok %d\n", test_num);
+ test_num++;
+}
+
+static void
+skip(int skip_num)
+{
+ int i;
+
+ for (i = 0; i < skip_num; i++) {
+ printf("not ok %d # SKIP\n", test_num);
+ test_num++;
+ }
+}
+
+static void
+snprintf__two_formatters(void)
+{
+ char buffer[128];
+
+ if (snprintf(buffer, sizeof(buffer), "%s, %s!", "Hello",
+ "tests") <= 0) {
+ fail("snprintf with two formatters failed");
+ skip(1);
+ } else {
+ pass();
+ if (strcmp(buffer, "Hello, tests!") != 0)
+ fail("Bad formatting: got %s", buffer);
+ else
+ pass();
+ }
+}
+
+static void
+snprintf__overflow(void)
+{
+ char buffer[10];
+
+ if (snprintf(buffer, sizeof(buffer), "0123456789abcdef") != 16) {
+ fail("snprintf did not return the expected "
+ "number of characters");
+ skip(1);
+ return;
+ }
+ pass();
+
+ if (strcmp(buffer, "012345678") != 0)
+ fail("Bad formatting: got %s", buffer);
+ else
+ pass();
+}
+
+static void
+fprintf__simple_string(void)
+{
+ FILE *file;
+ char buffer[128];
+ size_t length;
+ const char *contents = "This is a message\n";
+
+ file = fopen("test.txt", "w+");
+ if (fprintf(file, "%s", contents) <= 0) {
+ fail("fprintf failed to write to file");
+ skip(2);
+ return;
+ }
+ pass();
+ rewind(file);
+ length = fread(buffer, 1, sizeof(buffer) - 1, file);
+ if (length != strlen(contents)) {
+ fail("fread failed");
+ skip(1);
+ return;
+ }
+ pass();
+ buffer[length] = '\0';
+ fclose(file);
+
+ if (strcmp(buffer, contents) != 0)
+ fail("Written and read data differ");
+ else
+ pass();
+
+ /* Of special note here is that we are NOT deleting the temporary
+ * files we created in this test. Kyua takes care of this cleanup
+ * automatically and tests can (and should) rely on this behavior. */
+}
+
+int
+main(void)
+{
+ /* If you have read the printf_test.c counterpart in the atf/
+ * directory, you may think that the sequencing of tests below and
+ * the exposed behavior to the user is very similar. But you'd be
+ * wrong.
+ *
+ * There are two major differences with this and the ATF version.
+ * The first is that the code below has no provisions to detect
+ * failures in one test and continue running the other tests: the
+ * first failure causes the whole test program to exit. The second
+ * is that this particular main() has no arguments: without ATF,
+ * all test programs may expose a different command-line interface,
+ * and this is an issue for consistency purposes. */
+ printf("1..%d\n", TEST_COUNT);
+
+ snprintf__two_formatters();
+ snprintf__overflow();
+ fprintf__simple_string();
+
+ return (failed);
+}
diff --git a/share/examples/uefisign/uefikeys b/share/examples/uefisign/uefikeys
new file mode 100755
index 000000000000..ac97f2cfb3fa
--- /dev/null
+++ b/share/examples/uefisign/uefikeys
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# See uefisign(8) manual page for usage instructions.
+#
+#
+
+die() {
+ echo "$*" > /dev/stderr
+ exit 1
+}
+
+if [ $# -ne 1 ]; then
+ echo "usage: $0 common-name"
+ exit 1
+fi
+
+certfile="${1}.pem"
+efifile="${1}.cer"
+keyfile="${1}.key"
+# XXX: Set this to ten years; we don't want system to suddenly stop booting
+# due to certificate expiration. Better way would be to use Authenticode
+# Timestamp. That said, the rumor is UEFI implementations ignore it anyway.
+days="3650"
+subj="/CN=${1}"
+
+[ ! -e "${certfile}" ] || die "${certfile} already exists"
+[ ! -e "${efifile}" ] || die "${efifile} already exists"
+[ ! -e "${keyfile}" ] || die "${keyfile} already exists"
+
+umask 077 || die "umask 077 failed"
+
+openssl genrsa -out "${keyfile}" 2048 2> /dev/null || die "openssl genrsa failed"
+openssl req -new -x509 -sha256 -days "${days}" -subj "${subj}" -key "${keyfile}" -out "${certfile}" || die "openssl req failed"
+openssl x509 -inform PEM -outform DER -in "${certfile}" -out "${efifile}" || die "openssl x509 failed"
+
+echo "certificate: ${certfile}; private key: ${keyfile}; certificate to enroll in UEFI: ${efifile}"
diff --git a/share/examples/witness/lockgraphs.sh b/share/examples/witness/lockgraphs.sh
new file mode 100644
index 000000000000..cbb229228273
--- /dev/null
+++ b/share/examples/witness/lockgraphs.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+################################################################################
+#
+# lockgraphs.sh by Michele Dallachiesa -- 2008-05-07 -- v0.1
+#
+#
+################################################################################
+
+sysctl debug.witness.graphs | awk '
+BEGIN {
+ print "digraph lockgraphs {"
+ }
+
+NR > 1 && $0 ~ /"Giant"/ {
+ gsub(","," -> ");
+ print $0 ";"
+}
+
+END {
+ print "}"
+ }'
+
+#eof
diff --git a/share/examples/ypldap/ypldap.conf b/share/examples/ypldap/ypldap.conf
new file mode 100644
index 000000000000..46c6cf0d83eb
--- /dev/null
+++ b/share/examples/ypldap/ypldap.conf
@@ -0,0 +1,39 @@
+domain "freebsd.org"
+interval 60
+provide map "passwd.byname"
+provide map "passwd.byuid"
+provide map "group.byname"
+provide map "group.bygid"
+provide map "netid.byname"
+
+directory "127.0.0.1" {
+ # directory options
+ binddn "cn=ldap,dc=freebsd,dc=org"
+ bindcred "secret"
+ basedn "dc=freebsd.,dc=org"
+ # starting point for groups directory search, default to basedn
+ groupdn "ou=Groups,dc=freebsd,dc=org"
+
+ # passwd maps configuration (RFC 2307 posixAccount object class)
+ passwd filter "(objectClass=posixAccount)"
+
+ attribute name maps to "uid"
+ fixed attribute passwd "*"
+ attribute uid maps to "uidNumber"
+ attribute gid maps to "gidNumber"
+ attribute gecos maps to "cn"
+ attribute home maps to "homeDirectory"
+ attribute shell maps to "loginShell"
+ fixed attribute change "0"
+ fixed attribute expire "0"
+ fixed attribute class ""
+
+ # group maps configuration (RFC 2307 posixGroup object class)
+ group filter "(objectClass=posixGroup)"
+
+ attribute groupname maps to "cn"
+ fixed attribute grouppasswd "*"
+ attribute groupgid maps to "gidNumber"
+ # memberUid returns multiple group members
+ list groupmembers maps to "memberUid"
+}